From python-checkins at python.org Mon Jul 1 00:38:19 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 1 Jul 2013 00:38:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MTg5?= =?utf-8?q?=3A_add_test=5Fdelegator_for_Idle_Delegator_class=2E?= Message-ID: <3bk67H5QwNz7LnM@mail.python.org> http://hg.python.org/cpython/rev/231c122b44b6 changeset: 84399:231c122b44b6 branch: 2.7 parent: 84392:a568a5426a16 user: Terry Jan Reedy date: Sun Jun 30 18:36:53 2013 -0400 summary: Issue #18189: add test_delegator for Idle Delegator class. Also change private dict used as a set to a set. files: Lib/idlelib/Delegator.py | 6 +- Lib/idlelib/idle_test/test_delegator.py | 37 +++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/Delegator.py b/Lib/idlelib/Delegator.py --- a/Lib/idlelib/Delegator.py +++ b/Lib/idlelib/Delegator.py @@ -4,16 +4,16 @@ def __init__(self, delegate=None): self.delegate = delegate - self.__cache = {} + self.__cache = set() def __getattr__(self, name): attr = getattr(self.delegate, name) # May raise AttributeError setattr(self, name, attr) - self.__cache[name] = attr + self.__cache.add(name) return attr def resetcache(self): - for key in self.__cache.keys(): + for key in self.__cache: try: delattr(self, key) except AttributeError: diff --git a/Lib/idlelib/idle_test/test_delegator.py b/Lib/idlelib/idle_test/test_delegator.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_delegator.py @@ -0,0 +1,37 @@ +import unittest +from idlelib.Delegator import Delegator + +class DelegatorTest(unittest.TestCase): + + def test_mydel(self): + # test a simple use scenario + + # initialize + mydel = Delegator(int) + self.assertIs(mydel.delegate, int) + self.assertEqual(mydel._Delegator__cache, set()) + + # add an attribute: + self.assertRaises(AttributeError, mydel.__getattr__, 'xyz') + bl = mydel.bit_length + self.assertIs(bl, int.bit_length) + self.assertIs(mydel.__dict__['bit_length'], int.bit_length) + self.assertEqual(mydel._Delegator__cache, {'bit_length'}) + + # add a second attribute + mydel.numerator + self.assertEqual(mydel._Delegator__cache, {'bit_length', 'numerator'}) + + # delete the second (which, however, leaves it in the name cache) + del mydel.numerator + self.assertNotIn('numerator', mydel.__dict__) + self.assertIn('numerator', mydel._Delegator__cache) + + # reset by calling .setdelegate, which calls .resetcache + mydel.setdelegate(float) + self.assertIs(mydel.delegate, float) + self.assertNotIn('bit_length', mydel.__dict__) + self.assertEqual(mydel._Delegator__cache, set()) + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=2) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 00:38:21 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 1 Jul 2013 00:38:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MTg5?= =?utf-8?q?=3A_add_test=5Fdelegator_for_Idle_Delegator_class=2E?= Message-ID: <3bk67K0FNdz7Lnc@mail.python.org> http://hg.python.org/cpython/rev/c7605471e8ae changeset: 84400:c7605471e8ae branch: 3.3 parent: 84397:c17fa2cbad43 user: Terry Jan Reedy date: Sun Jun 30 18:37:05 2013 -0400 summary: Issue #18189: add test_delegator for Idle Delegator class. Also change private dict used as a set to a set. files: Lib/idlelib/Delegator.py | 4 +- Lib/idlelib/idle_test/test_delegator.py | 37 +++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/Delegator.py b/Lib/idlelib/Delegator.py --- a/Lib/idlelib/Delegator.py +++ b/Lib/idlelib/Delegator.py @@ -4,12 +4,12 @@ def __init__(self, delegate=None): self.delegate = delegate - self.__cache = {} + self.__cache = set() def __getattr__(self, name): attr = getattr(self.delegate, name) # May raise AttributeError setattr(self, name, attr) - self.__cache[name] = attr + self.__cache.add(name) return attr def resetcache(self): diff --git a/Lib/idlelib/idle_test/test_delegator.py b/Lib/idlelib/idle_test/test_delegator.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_delegator.py @@ -0,0 +1,37 @@ +import unittest +from idlelib.Delegator import Delegator + +class DelegatorTest(unittest.TestCase): + + def test_mydel(self): + # test a simple use scenario + + # initialize + mydel = Delegator(int) + self.assertIs(mydel.delegate, int) + self.assertEqual(mydel._Delegator__cache, set()) + + # add an attribute: + self.assertRaises(AttributeError, mydel.__getattr__, 'xyz') + bl = mydel.bit_length + self.assertIs(bl, int.bit_length) + self.assertIs(mydel.__dict__['bit_length'], int.bit_length) + self.assertEqual(mydel._Delegator__cache, {'bit_length'}) + + # add a second attribute + mydel.numerator + self.assertEqual(mydel._Delegator__cache, {'bit_length', 'numerator'}) + + # delete the second (which, however, leaves it in the name cache) + del mydel.numerator + self.assertNotIn('numerator', mydel.__dict__) + self.assertIn('numerator', mydel._Delegator__cache) + + # reset by calling .setdelegate, which calls .resetcache + mydel.setdelegate(float) + self.assertIs(mydel.delegate, float) + self.assertNotIn('bit_length', mydel.__dict__) + self.assertEqual(mydel._Delegator__cache, set()) + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=2) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 00:38:22 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 1 Jul 2013 00:38:22 +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: <3bk67L25v2z7LnM@mail.python.org> http://hg.python.org/cpython/rev/dbdb6f7f9a1a changeset: 84401:dbdb6f7f9a1a parent: 84398:ae69436eb7c2 parent: 84400:c7605471e8ae user: Terry Jan Reedy date: Sun Jun 30 18:37:51 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/Delegator.py | 4 +- Lib/idlelib/idle_test/test_delegator.py | 37 +++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/Delegator.py b/Lib/idlelib/Delegator.py --- a/Lib/idlelib/Delegator.py +++ b/Lib/idlelib/Delegator.py @@ -4,12 +4,12 @@ def __init__(self, delegate=None): self.delegate = delegate - self.__cache = {} + self.__cache = set() def __getattr__(self, name): attr = getattr(self.delegate, name) # May raise AttributeError setattr(self, name, attr) - self.__cache[name] = attr + self.__cache.add(name) return attr def resetcache(self): diff --git a/Lib/idlelib/idle_test/test_delegator.py b/Lib/idlelib/idle_test/test_delegator.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_delegator.py @@ -0,0 +1,37 @@ +import unittest +from idlelib.Delegator import Delegator + +class DelegatorTest(unittest.TestCase): + + def test_mydel(self): + # test a simple use scenario + + # initialize + mydel = Delegator(int) + self.assertIs(mydel.delegate, int) + self.assertEqual(mydel._Delegator__cache, set()) + + # add an attribute: + self.assertRaises(AttributeError, mydel.__getattr__, 'xyz') + bl = mydel.bit_length + self.assertIs(bl, int.bit_length) + self.assertIs(mydel.__dict__['bit_length'], int.bit_length) + self.assertEqual(mydel._Delegator__cache, {'bit_length'}) + + # add a second attribute + mydel.numerator + self.assertEqual(mydel._Delegator__cache, {'bit_length', 'numerator'}) + + # delete the second (which, however, leaves it in the name cache) + del mydel.numerator + self.assertNotIn('numerator', mydel.__dict__) + self.assertIn('numerator', mydel._Delegator__cache) + + # reset by calling .setdelegate, which calls .resetcache + mydel.setdelegate(float) + self.assertIs(mydel.delegate, float) + self.assertNotIn('bit_length', mydel.__dict__) + self.assertEqual(mydel._Delegator__cache, set()) + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=2) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 01:08:18 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 1 Jul 2013 01:08:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzg1MTU6?= =?utf-8?q?_Set_=5F=5Ffile=5F=5F_when_run_file_in_IDLE=2E_Backport_2c276d0?= =?utf-8?q?553ff_by?= Message-ID: <3bk6nt4kTkz7LmZ@mail.python.org> http://hg.python.org/cpython/rev/a958b7f16a7d changeset: 84402:a958b7f16a7d branch: 2.7 parent: 84399:231c122b44b6 user: Terry Jan Reedy date: Sun Jun 30 19:07:49 2013 -0400 summary: Issue #8515: Set __file__ when run file in IDLE. Backport 2c276d0553ff by Andrew Svetlov, based on initial patch by Bruce Frederiksen. files: Lib/idlelib/ScriptBinding.py | 12 ++++++------ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -152,16 +152,16 @@ dirname = os.path.dirname(filename) # XXX Too often this discards arguments the user just set... interp.runcommand("""if 1: - _filename = %r + __file__ = {filename!r} import sys as _sys from os.path import basename as _basename if (not _sys.argv or - _basename(_sys.argv[0]) != _basename(_filename)): - _sys.argv = [_filename] + _basename(_sys.argv[0]) != _basename(__file__)): + _sys.argv = [__file__] import os as _os - _os.chdir(%r) - del _filename, _sys, _basename, _os - \n""" % (filename, dirname)) + _os.chdir({dirname!r}) + del _sys, _basename, _os + \n""".format(filename=filename, dirname=dirname)) interp.prepend_syspath(filename) # XXX KBK 03Jul04 When run w/o subprocess, runtime warnings still # go to __stderr__. With subprocess, they go to the shell. diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -317,6 +317,7 @@ John Fouhy Stefan Franke Martin Franklin +Bruce Frederiksen Robin Friedrich Bradley Froehle Ivan Frohne diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -73,6 +73,9 @@ IDLE ---- +- Issue #8515: Set __file__ when run file in IDLE. + Initial patch by Bruce Frederiksen. + - Issue #5492: Avoid traceback when exiting IDLE caused by a race condition. - Issue #17511: Keep IDLE find dialog open after clicking "Find Next". -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Jul 1 05:45:20 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 01 Jul 2013 05:45:20 +0200 Subject: [Python-checkins] Daily reference leaks (dbdb6f7f9a1a): sum=0 Message-ID: results for dbdb6f7f9a1a on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloguuf90q', '-x'] From python-checkins at python.org Mon Jul 1 06:52:44 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 1 Jul 2013 06:52:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzcxMzY6?= =?utf-8?q?_In_the_Idle_File_menu=2C_=22New_Window=22_is_renamed_=22New_Fi?= =?utf-8?q?le=22=2E?= Message-ID: <3bkGRJ1p8Rz7Lkw@mail.python.org> http://hg.python.org/cpython/rev/26ef5d5d5c3e changeset: 84403:26ef5d5d5c3e branch: 2.7 user: Terry Jan Reedy date: Mon Jul 01 00:42:44 2013 -0400 summary: Issue #7136: In the Idle File menu, "New Window" is renamed "New File". Patch by Tal Einat, Roget Serwy, and Todd Rovito. files: Doc/library/idle.rst | 4 ++-- Lib/idlelib/Bindings.py | 2 +- Lib/idlelib/help.txt | 2 +- Misc/NEWS | 3 +++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -33,8 +33,8 @@ File menu ^^^^^^^^^ -New window - create a new editing window +New file + create a new file editing window Open... open an existing file diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py --- a/Lib/idlelib/Bindings.py +++ b/Lib/idlelib/Bindings.py @@ -15,7 +15,7 @@ menudefs = [ # underscore prefixes character to underscore ('file', [ - ('_New Window', '<>'), + ('_New File', '<>'), ('_Open...', '<>'), ('Open _Module...', '<>'), ('Class _Browser', '<>'), diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -5,7 +5,7 @@ File Menu: - New Window -- Create a new editing window + New File -- Create a new editing window Open... -- Open an existing file Recent Files... -- Open a list of recent files Open Module... -- Open an existing module (searches sys.path) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -73,6 +73,9 @@ IDLE ---- +- Issue #7136: In the Idle File menu, "New Window" is renamed "New File". + Patch by Tal Einat, Roget Serwy, and Todd Rovito. + - Issue #8515: Set __file__ when run file in IDLE. Initial patch by Bruce Frederiksen. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 06:52:45 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 1 Jul 2013 06:52:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzcxMzY6?= =?utf-8?q?_In_the_Idle_File_menu=2C_=22New_Window=22_is_renamed_=22New_Fi?= =?utf-8?q?le=22=2E?= Message-ID: <3bkGRK3tzmz7Llg@mail.python.org> http://hg.python.org/cpython/rev/c39ddff53694 changeset: 84404:c39ddff53694 branch: 3.3 parent: 84400:c7605471e8ae user: Terry Jan Reedy date: Mon Jul 01 00:42:52 2013 -0400 summary: Issue #7136: In the Idle File menu, "New Window" is renamed "New File". Patch by Tal Einat, Roget Serwy, and Todd Rovito. files: Doc/library/idle.rst | 4 ++-- Lib/idlelib/Bindings.py | 2 +- Lib/idlelib/help.txt | 2 +- Misc/NEWS | 3 +++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -33,8 +33,8 @@ File menu ^^^^^^^^^ -New window - create a new editing window +New file + create a new file editing window Open... open an existing file diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py --- a/Lib/idlelib/Bindings.py +++ b/Lib/idlelib/Bindings.py @@ -15,7 +15,7 @@ menudefs = [ # underscore prefixes character to underscore ('file', [ - ('_New Window', '<>'), + ('_New File', '<>'), ('_Open...', '<>'), ('Open _Module...', '<>'), ('Class _Browser', '<>'), diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -5,7 +5,7 @@ File Menu: - New Window -- Create a new editing window + New File -- Create a new file editing window Open... -- Open an existing file Recent Files... -- Open a list of recent files Open Module... -- Open an existing module (searches sys.path) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -116,6 +116,9 @@ IDLE ---- +- Issue #7136: In the Idle File menu, "New Window" is renamed "New File". + Patch by Tal Einat, Roget Serwy, and Todd Rovito. + - Remove dead imports of imp. - Issue #18196: Avoid displaying spurious SystemExit tracebacks. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 06:52:46 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 1 Jul 2013 06:52:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28merge=29_Issue_=237136=3A_In_the_Idle_File_menu=2C_?= =?utf-8?q?=22New_Window=22_is_renamed_=22New_File=22=2E?= Message-ID: <3bkGRL5rkCz7Lpd@mail.python.org> http://hg.python.org/cpython/rev/5bc3d8d22a93 changeset: 84405:5bc3d8d22a93 parent: 84401:dbdb6f7f9a1a parent: 84404:c39ddff53694 user: Terry Jan Reedy date: Mon Jul 01 00:52:18 2013 -0400 summary: (merge) Issue #7136: In the Idle File menu, "New Window" is renamed "New File". Patch by Tal Einat, Roget Serwy, and Todd Rovito. files: Doc/library/idle.rst | 4 ++-- Lib/idlelib/Bindings.py | 2 +- Lib/idlelib/help.txt | 2 +- Misc/NEWS | 3 +++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -39,8 +39,8 @@ File menu (Shell and Editor) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -New window - Create a new editing window +New file + Create a new file editing window Open... Open an existing file diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py --- a/Lib/idlelib/Bindings.py +++ b/Lib/idlelib/Bindings.py @@ -15,7 +15,7 @@ menudefs = [ # underscore prefixes character to underscore ('file', [ - ('_New Window', '<>'), + ('_New File', '<>'), ('_Open...', '<>'), ('Open _Module...', '<>'), ('Class _Browser', '<>'), diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -21,7 +21,7 @@ File Menu (Shell and Editor): - New Window -- Create a new editing window + New File -- Create a new file editing window Open... -- Open an existing file Open Module... -- Open an existing module (searches sys.path) Recent Files... -- Open a list of recent files diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -543,6 +543,9 @@ IDLE ---- +- Issue #7136: In the Idle File menu, "New Window" is renamed "New File". + Patch by Tal Einat, Roget Serwy, and Todd Rovito. + - Remove dead imports of imp. - Issue #18196: Avoid displaying spurious SystemExit tracebacks. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 13:08:57 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 1 Jul 2013 13:08:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_18240=3A_The_HMAC_mo?= =?utf-8?q?dule_is_no_longer_restricted_to_bytes_and_accepts?= Message-ID: <3bkQnP0KNnz7LkG@mail.python.org> http://hg.python.org/cpython/rev/636947fe131e changeset: 84406:636947fe131e user: Christian Heimes date: Mon Jul 01 13:08:42 2013 +0200 summary: Issue 18240: The HMAC module is no longer restricted to bytes and accepts any bytes-like object, e.g. memoryview. Original patch by Jonas Borgstr?m. files: Doc/library/hmac.rst | 18 ++++++++++++------ Lib/hmac.py | 8 +++----- Lib/test/test_hmac.py | 14 ++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Doc/library/hmac.rst b/Doc/library/hmac.rst --- a/Doc/library/hmac.rst +++ b/Doc/library/hmac.rst @@ -16,20 +16,26 @@ .. function:: new(key, msg=None, digestmod=None) - Return a new hmac object. *key* is a bytes object giving the secret key. If - *msg* is present, the method call ``update(msg)`` is made. *digestmod* is - the digest constructor or module for the HMAC object to use. It defaults to - the :func:`hashlib.md5` constructor. + Return a new hmac object. *key* is a bytes or bytearray object giving the + secret key. If *msg* is present, the method call ``update(msg)`` is made. + *digestmod* is the digest constructor or module for the HMAC object to use. + It defaults to the :func:`hashlib.md5` constructor. + .. versionchanged:: 3.4 + Parameter *key* can be a bytes or bytearray object. Parameter *msg* can + be of any type supported by :mod:`hashlib`. An HMAC object has the following methods: .. method:: HMAC.update(msg) - Update the hmac object with the bytes object *msg*. Repeated calls are - equivalent to a single call with the concatenation of all the arguments: + Update the hmac object with *msg*. Repeated calls are equivalent to a + single call with the concatenation of all the arguments: ``m.update(a); m.update(b)`` is equivalent to ``m.update(a + b)``. + .. versionchanged:: 3.4 + Parameter *msg* can be of any type supported by :mod:`hashlib`. + .. method:: HMAC.digest() diff --git a/Lib/hmac.py b/Lib/hmac.py --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -31,11 +31,11 @@ A hashlib constructor returning a new hash object. Defaults to hashlib.md5. - Note: key and msg must be bytes objects. + Note: key and msg must be a bytes or bytearray objects. """ - if not isinstance(key, bytes): - raise TypeError("key: expected bytes, but got %r" % type(key).__name__) + if not isinstance(key, (bytes, bytearray)): + raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) if digestmod is None: import hashlib @@ -75,8 +75,6 @@ def update(self, msg): """Update this hashing object with the string msg. """ - if not isinstance(msg, bytes): - raise TypeError("expected bytes, but got %r" % type(msg).__name__) self.inner.update(msg) def copy(self): diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py @@ -253,6 +253,20 @@ except: self.fail("Constructor call with text argument raised exception.") + def test_with_bytearray(self): + try: + h = hmac.HMAC(bytearray(b"key"), bytearray(b"hash this!")) + self.assertEqual(h.hexdigest(), '34325b639da4cfd95735b381e28cb864') + except: + self.fail("Constructor call with bytearray arguments raised exception.") + + def test_with_memoryview_msg(self): + try: + h = hmac.HMAC(b"key", memoryview(b"hash this!")) + self.assertEqual(h.hexdigest(), '34325b639da4cfd95735b381e28cb864') + except: + self.fail("Constructor call with memoryview msg raised exception.") + def test_withmodule(self): # Constructor call with text and digest module. try: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -138,6 +138,7 @@ Forest Bond Gregory Bond Matias Bordese +Jonas Borgstr?m Jurjen Bos Peter Bosch Dan Boswell diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -135,6 +135,9 @@ Library ------- +- Issue 18240: The HMAC module is no longer restricted to bytes and accepts + any bytes-like object, e.g. memoryview. Original patch by Jonas Borgstr?m. + - Issue #18224: Removed pydoc script from created venv, as it causes problems on Windows and adds no value over and above python -m pydoc ... -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 14:46:25 2013 From: python-checkins at python.org (lukasz.langa) Date: Mon, 1 Jul 2013 14:46:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Use_C3-based_linearization_fo?= =?utf-8?q?r_ABC_support_to_improve_predictability?= Message-ID: <3bkSxs70tYz7LkL@mail.python.org> http://hg.python.org/peps/rev/000a8986ef73 changeset: 4968:000a8986ef73 user: ?ukasz Langa date: Mon Jul 01 14:46:15 2013 +0200 summary: Use C3-based linearization for ABC support to improve predictability files: pep-0443.txt | 73 ++++++++++++++++++++++----------------- 1 files changed, 41 insertions(+), 32 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -193,48 +193,37 @@ importantly, it introduces support for Abstract Base Classes (ABC). 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:: +dispatch algorithm switches to an extended form of C3 linearization, +which includes the relevant ABCs in the MRO of the provided argument. +The algorithm inserts ABCs where their functionality is introduced, i.e. +``issubclass(cls, abc)`` returns ``True`` for the class itself but +returns ``False`` for all its direct base classes. Implicit ABCs for +a given class (either registered or inferred from the presence of +a special method like ``__len__()``) are inserted directly after the +last ABC explicitly listed in the MRO of said class. - 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 - -In its most basic form, it returns the MRO for the given type:: +In its most basic form, this linearization 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:: +When the second argument contains 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, all dispatch decisions are cached. The cache is invalidated on registering new 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:: +``register()`` on an ABC to implicitly subclass it. In the latter case, +it is possible to create a situation with ambiguous dispatch, for +instance:: >>> from collections import Iterable, Container >>> class P: @@ -261,20 +250,38 @@ 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:: +Note that this exception would not be raised if one or more ABCs had +been provided explicitly 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) + ... return value in range(10) ... >>> g(Ten()) 'iterable' +A similar conflict arises when subclassing an ABC is inferred from the +presence of a special method like ``__len__()`` or ``__contains__()``:: + + >>> class Q: + ... def __contains__(self, value): + ... return False + ... + >>> issubclass(Q, Container) + True + >>> Iterable.register(Q) + >>> g(Q()) + Traceback (most recent call last): + ... + RuntimeError: Ambiguous dispatch: + or + +An early version of the PEP contained a custom approach that was simpler +but created a number of edge cases with surprising results [#why-c3]_. Usage Patterns ============== @@ -378,6 +385,8 @@ a particular annotation style". (http://www.python.org/dev/peps/pep-0008) +.. [#why-c3] http://bugs.python.org/issue18244 + .. [#pep-3124] http://www.python.org/dev/peps/pep-3124/ .. [#peak-rules] http://peak.telecommunity.com/DevCenter/PEAK_2dRules -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 1 15:19:00 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 1 Jul 2013 15:19:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzM5?= =?utf-8?q?=3A_Negative_ints_keys_in_unpickler=2Ememo_dict_no_longer_cause?= =?utf-8?q?_a?= Message-ID: <3bkTgS1264zLrK@mail.python.org> http://hg.python.org/cpython/rev/17b7af660f82 changeset: 84407:17b7af660f82 branch: 3.3 parent: 84404:c39ddff53694 user: Christian Heimes date: Mon Jul 01 15:17:45 2013 +0200 summary: Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a segfault inside the _pickle C extension. files: Lib/test/test_pickle.py | 7 +++++++ Misc/NEWS | 3 +++ Modules/_pickle.c | 5 +++++ 3 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -115,6 +115,13 @@ pickler_class = _pickle.Pickler unpickler_class = _pickle.Unpickler + def test_issue18339(self): + unpickler = self.unpickler_class(io.BytesIO()) + self.assertRaises(TypeError, setattr, unpickler, "memo", object) + # used to cause a segfault + self.assertRaises(ValueError, setattr, unpickler, "memo", {-1: None}) + unpickler.memo = {1: None} + class CDispatchTableTests(AbstractDispatchTableTests): pickler_class = pickle.Pickler def get_dispatch_table(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,9 @@ Library ------- +- Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a + segfault inside the _pickle C extension. + - Issue #18224: Removed pydoc script from created venv, as it causes problems on Windows and adds no value over and above python -m pydoc ... diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -5931,6 +5931,11 @@ idx = PyLong_AsSsize_t(key); if (idx == -1 && PyErr_Occurred()) goto error; + if (idx < 0) { + PyErr_SetString(PyExc_ValueError, + "memos key must be positive integers."); + goto error; + } if (_Unpickler_MemoPut(self, idx, value) < 0) goto error; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 15:19:01 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 1 Jul 2013 15:19:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318339=3A_Negative_ints_keys_in_unpickler=2Ememo?= =?utf-8?q?_dict_no_longer_cause_a?= Message-ID: <3bkTgT4JDJz7Lkr@mail.python.org> http://hg.python.org/cpython/rev/f3372692ca20 changeset: 84408:f3372692ca20 parent: 84406:636947fe131e parent: 84407:17b7af660f82 user: Christian Heimes date: Mon Jul 01 15:18:49 2013 +0200 summary: Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a segfault inside the _pickle C extension. files: Lib/test/test_pickle.py | 7 +++++++ Misc/NEWS | 3 +++ Modules/_pickle.c | 5 +++++ 3 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -115,6 +115,13 @@ pickler_class = _pickle.Pickler unpickler_class = _pickle.Unpickler + def test_issue18339(self): + unpickler = self.unpickler_class(io.BytesIO()) + self.assertRaises(TypeError, setattr, unpickler, "memo", object) + # used to cause a segfault + self.assertRaises(ValueError, setattr, unpickler, "memo", {-1: None}) + unpickler.memo = {1: None} + class CDispatchTableTests(AbstractDispatchTableTests): pickler_class = pickle.Pickler def get_dispatch_table(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -135,6 +135,9 @@ Library ------- +- Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a + segfault inside the _pickle C extension. + - Issue 18240: The HMAC module is no longer restricted to bytes and accepts any bytes-like object, e.g. memoryview. Original patch by Jonas Borgstr?m. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -5952,6 +5952,11 @@ idx = PyLong_AsSsize_t(key); if (idx == -1 && PyErr_Occurred()) goto error; + if (idx < 0) { + PyErr_SetString(PyExc_ValueError, + "memos key must be positive integers."); + goto error; + } if (_Unpickler_MemoPut(self, idx, value) < 0) goto error; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 15:24:07 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 1 Jul 2013 15:24:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Singular_form_?= =?utf-8?q?just_like_the_other_error_message=2E?= Message-ID: <3bkTnM3ccBz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/61b6cd7b9819 changeset: 84409:61b6cd7b9819 branch: 3.3 parent: 84407:17b7af660f82 user: Christian Heimes date: Mon Jul 01 15:23:39 2013 +0200 summary: Singular form just like the other error message. files: Modules/_pickle.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -5933,7 +5933,7 @@ goto error; if (idx < 0) { PyErr_SetString(PyExc_ValueError, - "memos key must be positive integers."); + "memo key must be positive integers."); goto error; } if (_Unpickler_MemoPut(self, idx, value) < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 15:24:08 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 1 Jul 2013 15:24:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Singular_form_just_like_the_other_error_message=2E?= Message-ID: <3bkTnN6vzPz7LkK@mail.python.org> http://hg.python.org/cpython/rev/f17647ce8f8a changeset: 84410:f17647ce8f8a parent: 84408:f3372692ca20 parent: 84409:61b6cd7b9819 user: Christian Heimes date: Mon Jul 01 15:23:48 2013 +0200 summary: Singular form just like the other error message. files: Modules/_pickle.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -5954,7 +5954,7 @@ goto error; if (idx < 0) { PyErr_SetString(PyExc_ValueError, - "memos key must be positive integers."); + "memo key must be positive integers."); goto error; } if (_Unpickler_MemoPut(self, idx, value) < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 16:03:39 2013 From: python-checkins at python.org (lukasz.langa) Date: Mon, 1 Jul 2013 16:03:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318244=3A_Adopt_C3?= =?utf-8?q?-based_linearization_in_functools=2Esingledispatch_for?= Message-ID: <3bkVfz4jBQz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/a2672dc7c805 changeset: 84411:a2672dc7c805 parent: 84406:636947fe131e user: ?ukasz Langa date: Mon Jul 01 16:00:38 2013 +0200 summary: Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support files: Lib/functools.py | 178 ++++++++++++++++++------ Lib/test/test_functools.py | 174 +++++++++++++++++++++-- Misc/ACKS | 1 + 3 files changed, 289 insertions(+), 64 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -365,46 +365,138 @@ ### singledispatch() - single-dispatch generic function decorator ################################################################################ -def _compose_mro(cls, haystack): - """Calculates the MRO for a given class `cls`, including relevant abstract - base classes from `haystack`. +def _c3_merge(sequences): + """Merges MROs in *sequences* to a single MRO using the C3 algorithm. + + Adapted from http://www.python.org/download/releases/2.3/mro/. + + """ + result = [] + while True: + sequences = [s for s in sequences if s] # purge empty sequences + if not sequences: + return result + for s1 in sequences: # find merge candidates among seq heads + candidate = s1[0] + for s2 in sequences: + if candidate in s2[1:]: + candidate = None + break # reject the current head, it appears later + else: + break + if not candidate: + raise RuntimeError("Inconsistent hierarchy") + result.append(candidate) + # remove the chosen candidate + for seq in sequences: + if seq[0] == candidate: + del seq[0] + +def _c3_mro(cls, abcs=None): + """Computes the method resolution order using extended C3 linearization. + + If no *abcs* are given, the algorithm works exactly like the built-in C3 + linearization used for method resolution. + + If given, *abcs* is a list of abstract base classes that should be inserted + into the resulting MRO. Unrelated ABCs are ignored and don't end up in the + result. The algorithm inserts ABCs where their functionality is introduced, + i.e. issubclass(cls, abc) returns True for the class itself but returns + False for all its direct base classes. Implicit ABCs for a given class + (either registered or inferred from the presence of a special method like + __len__) are inserted directly after the last ABC explicitly listed in the + MRO of said class. If two implicit ABCs end up next to each other in the + resulting MRO, their ordering depends on the order of types in *abcs*. + + """ + for i, base in enumerate(reversed(cls.__bases__)): + if hasattr(base, '__abstractmethods__'): + boundary = len(cls.__bases__) - i + break # Bases up to the last explicit ABC are considered first. + else: + boundary = 0 + abcs = list(abcs) if abcs else [] + explicit_bases = list(cls.__bases__[:boundary]) + abstract_bases = [] + other_bases = list(cls.__bases__[boundary:]) + for base in abcs: + if issubclass(cls, base) and not any( + issubclass(b, base) for b in cls.__bases__ + ): + # If *cls* is the class that introduces behaviour described by + # an ABC *base*, insert said ABC to its MRO. + abstract_bases.append(base) + for base in abstract_bases: + abcs.remove(base) + explicit_c3_mros = [_c3_mro(base, abcs=abcs) for base in explicit_bases] + abstract_c3_mros = [_c3_mro(base, abcs=abcs) for base in abstract_bases] + other_c3_mros = [_c3_mro(base, abcs=abcs) for base in other_bases] + return _c3_merge( + [[cls]] + + explicit_c3_mros + abstract_c3_mros + other_c3_mros + + [explicit_bases] + [abstract_bases] + [other_bases] + ) + +def _compose_mro(cls, types): + """Calculates the method resolution order for a given class *cls*. + + Includes relevant abstract base classes (with their respective bases) from + the *types* iterable. Uses a modified C3 linearization algorithm. """ bases = set(cls.__mro__) - mro = list(cls.__mro__) - for needle in haystack: - if (needle in bases or not hasattr(needle, '__mro__') - or not issubclass(cls, needle)): - continue # either present in the __mro__ already or unrelated - for index, base in enumerate(mro): - if not issubclass(base, needle): - break - if base in bases and not issubclass(needle, base): - # Conflict resolution: put classes present in __mro__ and their - # subclasses first. See test_mro_conflicts() in test_functools.py - # for examples. - index += 1 - mro.insert(index, needle) - return mro + # Remove entries which are already present in the __mro__ or unrelated. + def is_related(typ): + return (typ not in bases and hasattr(typ, '__mro__') + and issubclass(cls, typ)) + types = [n for n in types if is_related(n)] + # Remove entries which are strict bases of other entries (they will end up + # in the MRO anyway. + def is_strict_base(typ): + for other in types: + if typ != other and typ in other.__mro__: + return True + return False + types = [n for n in types if not is_strict_base(n)] + # Subclasses of the ABCs in *types* which are also implemented by + # *cls* can be used to stabilize ABC ordering. + type_set = set(types) + mro = [] + for typ in types: + found = [] + for sub in typ.__subclasses__(): + if sub not in bases and issubclass(cls, sub): + found.append([s for s in sub.__mro__ if s in type_set]) + if not found: + mro.append(typ) + continue + # Favor subclasses with the biggest number of useful bases + found.sort(key=len, reverse=True) + for sub in found: + for subcls in sub: + if subcls not in mro: + mro.append(subcls) + return _c3_mro(cls, abcs=mro) def _find_impl(cls, registry): - """Returns the best matching implementation for the given class `cls` in - `registry`. Where there is no registered implementation for a specific - type, its method resolution order is used to find a more generic - implementation. + """Returns the best matching implementation from *registry* for type *cls*. - Note: if `registry` does not contain an implementation for the base - `object` type, this function may return None. + Where there is no registered implementation for a specific type, its method + resolution order is used to find a more generic implementation. + + Note: if *registry* does not contain an implementation for the base + *object* type, this function may return None. """ mro = _compose_mro(cls, registry.keys()) match = None for t in mro: if match is not None: - # If `match` is an ABC but there is another unrelated, equally - # matching ABC. Refuse the temptation to guess. - if (t in registry and not issubclass(match, t) - and match not in cls.__mro__): + # If *match* is an implicit ABC but there is another unrelated, + # equally matching implicit ABC, refuse the temptation to guess. + if (t in registry and t not in cls.__mro__ + and match not in cls.__mro__ + and not issubclass(match, t)): raise RuntimeError("Ambiguous dispatch: {} or {}".format( match, t)) break @@ -418,19 +510,19 @@ Transforms a function into a generic function, which can have different behaviours depending upon the type of its first argument. The decorated function acts as the default implementation, and additional - implementations can be registered using the 'register()' attribute of - the generic function. + implementations can be registered using the register() attribute of the + generic function. """ registry = {} dispatch_cache = WeakKeyDictionary() cache_token = None - def dispatch(typ): - """generic_func.dispatch(type) -> + def dispatch(cls): + """generic_func.dispatch(cls) -> Runs the dispatch algorithm to return the best available implementation - for the given `type` registered on `generic_func`. + for the given *cls* registered on *generic_func*. """ nonlocal cache_token @@ -440,26 +532,26 @@ dispatch_cache.clear() cache_token = current_token try: - impl = dispatch_cache[typ] + impl = dispatch_cache[cls] except KeyError: try: - impl = registry[typ] + impl = registry[cls] except KeyError: - impl = _find_impl(typ, registry) - dispatch_cache[typ] = impl + impl = _find_impl(cls, registry) + dispatch_cache[cls] = impl return impl - def register(typ, func=None): - """generic_func.register(type, func) -> func + def register(cls, func=None): + """generic_func.register(cls, func) -> func - Registers a new implementation for the given `type` on a `generic_func`. + Registers a new implementation for the given *cls* on a *generic_func*. """ nonlocal cache_token if func is None: - return lambda f: register(typ, f) - registry[typ] = func - if cache_token is None and hasattr(typ, '__abstractmethods__'): + return lambda f: register(cls, f) + registry[cls] = func + if cache_token is None and hasattr(cls, '__abstractmethods__'): cache_token = get_cache_token() dispatch_cache.clear() return func diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -929,22 +929,55 @@ self.assertEqual(g(rnd), ("Number got rounded",)) def test_compose_mro(self): + # None of the examples in this test depend on haystack ordering. c = collections mro = functools._compose_mro bases = [c.Sequence, c.MutableMapping, c.Mapping, c.Set] for haystack in permutations(bases): m = mro(dict, haystack) - self.assertEqual(m, [dict, c.MutableMapping, c.Mapping, object]) + self.assertEqual(m, [dict, c.MutableMapping, c.Mapping, c.Sized, + c.Iterable, c.Container, object]) bases = [c.Container, c.Mapping, c.MutableMapping, c.OrderedDict] for haystack in permutations(bases): m = mro(c.ChainMap, haystack) self.assertEqual(m, [c.ChainMap, c.MutableMapping, c.Mapping, c.Sized, c.Iterable, c.Container, object]) - # Note: The MRO order below depends on haystack ordering. - m = mro(c.defaultdict, [c.Sized, c.Container, str]) - self.assertEqual(m, [c.defaultdict, dict, c.Container, c.Sized, object]) - m = mro(c.defaultdict, [c.Container, c.Sized, str]) - self.assertEqual(m, [c.defaultdict, dict, c.Sized, c.Container, object]) + + # If there's a generic function with implementations registered for + # both Sized and Container, passing a defaultdict to it results in an + # ambiguous dispatch which will cause a RuntimeError (see + # test_mro_conflicts). + bases = [c.Container, c.Sized, str] + for haystack in permutations(bases): + m = mro(c.defaultdict, [c.Sized, c.Container, str]) + self.assertEqual(m, [c.defaultdict, dict, c.Sized, c.Container, + object]) + + # MutableSequence below is registered directly on D. In other words, it + # preceeds MutableMapping which means single dispatch will always + # choose MutableSequence here. + class D(c.defaultdict): + pass + c.MutableSequence.register(D) + bases = [c.MutableSequence, c.MutableMapping] + for haystack in permutations(bases): + m = mro(D, bases) + self.assertEqual(m, [D, c.MutableSequence, c.Sequence, + c.defaultdict, dict, c.MutableMapping, + c.Mapping, c.Sized, c.Iterable, c.Container, + object]) + + # Container and Callable are registered on different base classes and + # a generic function supporting both should always pick the Callable + # implementation if a C instance is passed. + class C(c.defaultdict): + def __call__(self): + pass + bases = [c.Sized, c.Callable, c.Container, c.Mapping] + for haystack in permutations(bases): + m = mro(C, haystack) + self.assertEqual(m, [C, c.Callable, c.defaultdict, dict, c.Mapping, + c.Sized, c.Iterable, c.Container, object]) def test_register_abc(self): c = collections @@ -1040,17 +1073,37 @@ self.assertEqual(g(f), "frozen-set") self.assertEqual(g(t), "tuple") + def test_c3_abc(self): + c = collections + mro = functools._c3_mro + class A(object): + pass + class B(A): + def __len__(self): + return 0 # implies Sized + @c.Container.register + class C(object): + pass + class D(object): + pass # unrelated + class X(D, C, B): + def __call__(self): + pass # implies Callable + expected = [X, c.Callable, D, C, c.Container, B, c.Sized, A, object] + for abcs in permutations([c.Sized, c.Callable, c.Container]): + self.assertEqual(mro(X, abcs=abcs), expected) + # unrelated ABCs don't appear in the resulting MRO + many_abcs = [c.Mapping, c.Sized, c.Callable, c.Container, c.Iterable] + self.assertEqual(mro(X, abcs=many_abcs), expected) + def test_mro_conflicts(self): c = collections - @functools.singledispatch def g(arg): return "base" - class O(c.Sized): def __len__(self): return 0 - o = O() self.assertEqual(g(o), "base") g.register(c.Iterable, lambda arg: "iterable") @@ -1062,35 +1115,114 @@ self.assertEqual(g(o), "sized") # because it's explicitly in __mro__ c.Container.register(O) self.assertEqual(g(o), "sized") # see above: Sized is in __mro__ - + c.Set.register(O) + self.assertEqual(g(o), "set") # because c.Set is a subclass of + # c.Sized and c.Container class P: pass - p = P() self.assertEqual(g(p), "base") c.Iterable.register(P) self.assertEqual(g(p), "iterable") c.Container.register(P) - with self.assertRaises(RuntimeError) as re: + with self.assertRaises(RuntimeError) as re_one: g(p) - self.assertEqual( - str(re), - ("Ambiguous dispatch: " - "or "), - ) - + self.assertIn( + str(re_one.exception), + (("Ambiguous dispatch: " + "or "), + ("Ambiguous dispatch: " + "or ")), + ) class Q(c.Sized): def __len__(self): return 0 - q = Q() self.assertEqual(g(q), "sized") c.Iterable.register(Q) self.assertEqual(g(q), "sized") # because it's explicitly in __mro__ c.Set.register(Q) self.assertEqual(g(q), "set") # because c.Set is a subclass of - # c.Sized which is explicitly in - # __mro__ + # c.Sized and c.Iterable + @functools.singledispatch + def h(arg): + return "base" + @h.register(c.Sized) + def _(arg): + return "sized" + @h.register(c.Container) + def _(arg): + return "container" + # Even though Sized and Container are explicit bases of MutableMapping, + # this ABC is implicitly registered on defaultdict which makes all of + # MutableMapping's bases implicit as well from defaultdict's + # perspective. + with self.assertRaises(RuntimeError) as re_two: + h(c.defaultdict(lambda: 0)) + self.assertIn( + str(re_two.exception), + (("Ambiguous dispatch: " + "or "), + ("Ambiguous dispatch: " + "or ")), + ) + class R(c.defaultdict): + pass + c.MutableSequence.register(R) + @functools.singledispatch + def i(arg): + return "base" + @i.register(c.MutableMapping) + def _(arg): + return "mapping" + @i.register(c.MutableSequence) + def _(arg): + return "sequence" + r = R() + self.assertEqual(i(r), "sequence") + class S: + pass + class T(S, c.Sized): + def __len__(self): + return 0 + t = T() + self.assertEqual(h(t), "sized") + c.Container.register(T) + self.assertEqual(h(t), "sized") # because it's explicitly in the MRO + class U: + def __len__(self): + return 0 + u = U() + self.assertEqual(h(u), "sized") # implicit Sized subclass inferred + # from the existence of __len__() + c.Container.register(U) + # There is no preference for registered versus inferred ABCs. + with self.assertRaises(RuntimeError) as re_three: + h(u) + self.assertIn( + str(re_three.exception), + (("Ambiguous dispatch: " + "or "), + ("Ambiguous dispatch: " + "or ")), + ) + class V(c.Sized, S): + def __len__(self): + return 0 + @functools.singledispatch + def j(arg): + return "base" + @j.register(S) + def _(arg): + return "s" + @j.register(c.Container) + def _(arg): + return "container" + v = V() + self.assertEqual(j(v), "s") + c.Container.register(V) + self.assertEqual(j(v), "container") # because it ends up right after + # Sized in the MRO def test_cache_invalidation(self): from collections import UserDict diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -195,6 +195,7 @@ Mike Carlton Pierre Carrier Terry Carroll +Edward Catmur Lorenzo M. Catucci Donn Cave Charles Cazabon -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 16:03:41 2013 From: python-checkins at python.org (lukasz.langa) Date: Mon, 1 Jul 2013 16:03:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_current_default?= Message-ID: <3bkVg101cNz7LkS@mail.python.org> http://hg.python.org/cpython/rev/879ee6762f3d changeset: 84412:879ee6762f3d parent: 84411:a2672dc7c805 parent: 84410:f17647ce8f8a user: ?ukasz Langa date: Mon Jul 01 16:03:17 2013 +0200 summary: Merge with current default files: Lib/test/test_pickle.py | 7 +++++++ Misc/NEWS | 3 +++ Modules/_pickle.c | 5 +++++ 3 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -115,6 +115,13 @@ pickler_class = _pickle.Pickler unpickler_class = _pickle.Unpickler + def test_issue18339(self): + unpickler = self.unpickler_class(io.BytesIO()) + self.assertRaises(TypeError, setattr, unpickler, "memo", object) + # used to cause a segfault + self.assertRaises(ValueError, setattr, unpickler, "memo", {-1: None}) + unpickler.memo = {1: None} + class CDispatchTableTests(AbstractDispatchTableTests): pickler_class = pickle.Pickler def get_dispatch_table(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -135,6 +135,9 @@ Library ------- +- Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a + segfault inside the _pickle C extension. + - Issue 18240: The HMAC module is no longer restricted to bytes and accepts any bytes-like object, e.g. memoryview. Original patch by Jonas Borgstr?m. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -5952,6 +5952,11 @@ idx = PyLong_AsSsize_t(key); if (idx == -1 && PyErr_Occurred()) goto error; + if (idx < 0) { + PyErr_SetString(PyExc_ValueError, + "memo key must be positive integers."); + goto error; + } if (_Unpickler_MemoPut(self, idx, value) < 0) goto error; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 20:12:10 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 1 Jul 2013 20:12:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3MDk3?= =?utf-8?q?=3A_Make_multiprocessing_ignore_EINTR=2E?= Message-ID: <3bkc9k3GQlz7Ljx@mail.python.org> http://hg.python.org/cpython/rev/bc34fe4a0d58 changeset: 84413:bc34fe4a0d58 branch: 2.7 parent: 84403:26ef5d5d5c3e user: Richard Oudkerk date: Mon Jul 01 18:45:28 2013 +0100 summary: Issue #17097: Make multiprocessing ignore EINTR. files: Lib/multiprocessing/connection.py | 9 +- Lib/test/test_multiprocessing.py | 70 +++++++++- Misc/NEWS | 2 + Modules/_multiprocessing/socket_connection.c | 57 ++++++- 4 files changed, 127 insertions(+), 11 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -270,7 +270,14 @@ self._unlink = None def accept(self): - s, self._last_accepted = self._socket.accept() + while True: + try: + s, self._last_accepted = self._socket.accept() + except socket.error as e: + if e.args[0] != errno.EINTR: + raise + else: + break s.setblocking(True) fd = duplicate(s.fileno()) conn = _multiprocessing.Connection(fd) 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 @@ -2461,12 +2461,80 @@ self.assertLessEqual(new_size, old_size) # +# Issue #17097: EINTR should be ignored by recv(), send(), accept() etc +# + +class TestIgnoreEINTR(unittest.TestCase): + + @classmethod + def _test_ignore(cls, conn): + def handler(signum, frame): + pass + signal.signal(signal.SIGUSR1, handler) + conn.send('ready') + x = conn.recv() + conn.send(x) + conn.send_bytes(b'x'*(1024*1024)) # sending 1 MB should block + + @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1') + def test_ignore(self): + conn, child_conn = multiprocessing.Pipe() + try: + p = multiprocessing.Process(target=self._test_ignore, + args=(child_conn,)) + p.daemon = True + p.start() + child_conn.close() + self.assertEqual(conn.recv(), 'ready') + time.sleep(0.1) + os.kill(p.pid, signal.SIGUSR1) + time.sleep(0.1) + conn.send(1234) + self.assertEqual(conn.recv(), 1234) + time.sleep(0.1) + os.kill(p.pid, signal.SIGUSR1) + self.assertEqual(conn.recv_bytes(), b'x'*(1024*1024)) + time.sleep(0.1) + p.join() + finally: + conn.close() + + @classmethod + def _test_ignore_listener(cls, conn): + def handler(signum, frame): + pass + signal.signal(signal.SIGUSR1, handler) + l = multiprocessing.connection.Listener() + conn.send(l.address) + a = l.accept() + a.send('welcome') + + @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1') + def test_ignore_listener(self): + conn, child_conn = multiprocessing.Pipe() + try: + p = multiprocessing.Process(target=self._test_ignore_listener, + args=(child_conn,)) + p.daemon = True + p.start() + child_conn.close() + address = conn.recv() + time.sleep(0.1) + os.kill(p.pid, signal.SIGUSR1) + time.sleep(0.1) + client = multiprocessing.connection.Client(address) + self.assertEqual(client.recv(), 'welcome') + p.join() + finally: + conn.close() + +# # # testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, TestStdinBadfiledescriptor, TestTimeouts, TestNoForkBomb, - TestFlags, TestForkAwareThreadLock] + TestFlags, TestForkAwareThreadLock, TestIgnoreEINTR] # # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #17097: Make multiprocessing ignore EINTR. + - Issue #18155: The csv module now correctly handles csv files that use a delimiter character that has a special meaning in regexes, instead of throwing an exception. diff --git a/Modules/_multiprocessing/socket_connection.c b/Modules/_multiprocessing/socket_connection.c --- a/Modules/_multiprocessing/socket_connection.c +++ b/Modules/_multiprocessing/socket_connection.c @@ -23,6 +23,21 @@ #endif /* + * Wrapper for PyErr_CheckSignals() which can be called without the GIL + */ + +static int +check_signals(void) +{ + PyGILState_STATE state; + int res; + state = PyGILState_Ensure(); + res = PyErr_CheckSignals(); + PyGILState_Release(state); + return res; +} + +/* * Send string to file descriptor */ @@ -34,8 +49,14 @@ while (length > 0) { res = WRITE(h, p, length); - if (res < 0) + if (res < 0) { + if (errno == EINTR) { + if (check_signals() < 0) + return MP_EXCEPTION_HAS_BEEN_SET; + continue; + } return MP_SOCKET_ERROR; + } length -= res; p += res; } @@ -56,12 +77,16 @@ while (remaining > 0) { temp = READ(h, p, remaining); - if (temp <= 0) { - if (temp == 0) - return remaining == length ? - MP_END_OF_FILE : MP_EARLY_END_OF_FILE; - else - return temp; + if (temp < 0) { + if (errno == EINTR) { + if (check_signals() < 0) + return MP_EXCEPTION_HAS_BEEN_SET; + continue; + } + return temp; + } + else if (temp == 0) { + return remaining == length ? MP_END_OF_FILE : MP_EARLY_END_OF_FILE; } remaining -= temp; p += temp; @@ -171,9 +196,16 @@ p.revents = 0; if (timeout < 0) { - res = poll(&p, 1, -1); + do { + res = poll(&p, 1, -1); + } while (res < 0 && errno == EINTR); } else { res = poll(&p, 1, (int)(timeout * 1000 + 0.5)); + if (res < 0 && errno == EINTR) { + /* We were interrupted by a signal. Just indicate a + timeout even though we are early. */ + return FALSE; + } } if (res < 0) { @@ -209,12 +241,19 @@ FD_SET((SOCKET)conn->handle, &rfds); if (timeout < 0.0) { - res = select((int)conn->handle+1, &rfds, NULL, NULL, NULL); + do { + res = select((int)conn->handle+1, &rfds, NULL, NULL, NULL); + } while (res < 0 && errno == EINTR); } else { struct timeval tv; tv.tv_sec = (long)timeout; tv.tv_usec = (long)((timeout - tv.tv_sec) * 1e6 + 0.5); res = select((int)conn->handle+1, &rfds, NULL, NULL, &tv); + if (res < 0 && errno == EINTR) { + /* We were interrupted by a signal. Just indicate a + timeout even though we are early. */ + return FALSE; + } } if (res < 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 20:12:11 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 1 Jul 2013 20:12:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3MDk3?= =?utf-8?q?=3A_Make_multiprocessing_ignore_EINTR=2E?= Message-ID: <3bkc9l6lKJz7LkX@mail.python.org> http://hg.python.org/cpython/rev/3ec5267f51ff changeset: 84414:3ec5267f51ff branch: 3.3 parent: 84409:61b6cd7b9819 user: Richard Oudkerk date: Mon Jul 01 18:59:26 2013 +0100 summary: Issue #17097: Make multiprocessing ignore EINTR. files: Lib/multiprocessing/connection.py | 18 ++++- Lib/test/test_multiprocessing.py | 70 ++++++++++++++++++- Misc/NEWS | 2 + 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -366,7 +366,10 @@ def _send(self, buf, write=_write): remaining = len(buf) while True: - n = write(self._handle, buf) + try: + n = write(self._handle, buf) + except InterruptedError: + continue remaining -= n if remaining == 0: break @@ -377,7 +380,10 @@ handle = self._handle remaining = size while remaining > 0: - chunk = read(handle, remaining) + try: + chunk = read(handle, remaining) + except InterruptedError: + continue n = len(chunk) if n == 0: if remaining == size: @@ -581,7 +587,13 @@ self._unlink = None def accept(self): - s, self._last_accepted = self._socket.accept() + while True: + try: + s, self._last_accepted = self._socket.accept() + except InterruptedError: + pass + else: + break s.setblocking(True) return Connection(s.detach()) 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 @@ -3461,13 +3461,81 @@ self.assertLessEqual(new_size, old_size) # +# Issue #17097: EINTR should be ignored by recv(), send(), accept() etc +# + +class TestIgnoreEINTR(unittest.TestCase): + + @classmethod + def _test_ignore(cls, conn): + def handler(signum, frame): + pass + signal.signal(signal.SIGUSR1, handler) + conn.send('ready') + x = conn.recv() + conn.send(x) + conn.send_bytes(b'x'*(1024*1024)) # sending 1 MB should block + + @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1') + def test_ignore(self): + conn, child_conn = multiprocessing.Pipe() + try: + p = multiprocessing.Process(target=self._test_ignore, + args=(child_conn,)) + p.daemon = True + p.start() + child_conn.close() + self.assertEqual(conn.recv(), 'ready') + time.sleep(0.1) + os.kill(p.pid, signal.SIGUSR1) + time.sleep(0.1) + conn.send(1234) + self.assertEqual(conn.recv(), 1234) + time.sleep(0.1) + os.kill(p.pid, signal.SIGUSR1) + self.assertEqual(conn.recv_bytes(), b'x'*(1024*1024)) + time.sleep(0.1) + p.join() + finally: + conn.close() + + @classmethod + def _test_ignore_listener(cls, conn): + def handler(signum, frame): + pass + signal.signal(signal.SIGUSR1, handler) + l = multiprocessing.connection.Listener() + conn.send(l.address) + a = l.accept() + a.send('welcome') + + @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1') + def test_ignore_listener(self): + conn, child_conn = multiprocessing.Pipe() + try: + p = multiprocessing.Process(target=self._test_ignore_listener, + args=(child_conn,)) + p.daemon = True + p.start() + child_conn.close() + address = conn.recv() + time.sleep(0.1) + os.kill(p.pid, signal.SIGUSR1) + time.sleep(0.1) + client = multiprocessing.connection.Client(address) + self.assertEqual(client.recv(), 'welcome') + p.join() + finally: + conn.close() + +# # # testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, TestStdinBadfiledescriptor, TestWait, TestInvalidFamily, TestFlags, TestTimeouts, TestNoForkBomb, - TestForkAwareThreadLock] + TestForkAwareThreadLock, TestIgnoreEINTR] # # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,8 @@ Library ------- +- Issue #17097: Make multiprocessing ignore EINTR. + - Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a segfault inside the _pickle C extension. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 20:12:13 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 1 Jul 2013 20:12:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogSXNzdWUgIzE3MDk3OiBNZXJnZS4=?= Message-ID: <3bkc9n41pWz7LlC@mail.python.org> http://hg.python.org/cpython/rev/035577781505 changeset: 84415:035577781505 parent: 84412:879ee6762f3d parent: 84414:3ec5267f51ff user: Richard Oudkerk date: Mon Jul 01 19:10:39 2013 +0100 summary: Issue #17097: Merge. files: Lib/multiprocessing/connection.py | 18 ++++- Lib/test/test_multiprocessing.py | 70 ++++++++++++++++++- Misc/NEWS | 2 + 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -363,7 +363,10 @@ def _send(self, buf, write=_write): remaining = len(buf) while True: - n = write(self._handle, buf) + try: + n = write(self._handle, buf) + except InterruptedError: + continue remaining -= n if remaining == 0: break @@ -374,7 +377,10 @@ handle = self._handle remaining = size while remaining > 0: - chunk = read(handle, remaining) + try: + chunk = read(handle, remaining) + except InterruptedError: + continue n = len(chunk) if n == 0: if remaining == size: @@ -578,7 +584,13 @@ self._unlink = None def accept(self): - s, self._last_accepted = self._socket.accept() + while True: + try: + s, self._last_accepted = self._socket.accept() + except InterruptedError: + pass + else: + break s.setblocking(True) return Connection(s.detach()) 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 @@ -3514,13 +3514,81 @@ self.assertLessEqual(new_size, old_size) # +# Issue #17097: EINTR should be ignored by recv(), send(), accept() etc +# + +class TestIgnoreEINTR(unittest.TestCase): + + @classmethod + def _test_ignore(cls, conn): + def handler(signum, frame): + pass + signal.signal(signal.SIGUSR1, handler) + conn.send('ready') + x = conn.recv() + conn.send(x) + conn.send_bytes(b'x'*(1024*1024)) # sending 1 MB should block + + @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1') + def test_ignore(self): + conn, child_conn = multiprocessing.Pipe() + try: + p = multiprocessing.Process(target=self._test_ignore, + args=(child_conn,)) + p.daemon = True + p.start() + child_conn.close() + self.assertEqual(conn.recv(), 'ready') + time.sleep(0.1) + os.kill(p.pid, signal.SIGUSR1) + time.sleep(0.1) + conn.send(1234) + self.assertEqual(conn.recv(), 1234) + time.sleep(0.1) + os.kill(p.pid, signal.SIGUSR1) + self.assertEqual(conn.recv_bytes(), b'x'*(1024*1024)) + time.sleep(0.1) + p.join() + finally: + conn.close() + + @classmethod + def _test_ignore_listener(cls, conn): + def handler(signum, frame): + pass + signal.signal(signal.SIGUSR1, handler) + l = multiprocessing.connection.Listener() + conn.send(l.address) + a = l.accept() + a.send('welcome') + + @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1') + def test_ignore_listener(self): + conn, child_conn = multiprocessing.Pipe() + try: + p = multiprocessing.Process(target=self._test_ignore_listener, + args=(child_conn,)) + p.daemon = True + p.start() + child_conn.close() + address = conn.recv() + time.sleep(0.1) + os.kill(p.pid, signal.SIGUSR1) + time.sleep(0.1) + client = multiprocessing.connection.Client(address) + self.assertEqual(client.recv(), 'welcome') + p.join() + finally: + conn.close() + +# # # testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, TestStdinBadfiledescriptor, TestWait, TestInvalidFamily, TestFlags, TestTimeouts, TestNoForkBomb, - TestForkAwareThreadLock] + TestForkAwareThreadLock, TestIgnoreEINTR] # # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -135,6 +135,8 @@ Library ------- +- Issue #17097: Make multiprocessing ignore EINTR. + - Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a segfault inside the _pickle C extension. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 22:29:26 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 1 Jul 2013 22:29:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_445=3A_cleanup?= Message-ID: <3bkgD63LG2z7Ljg@mail.python.org> http://hg.python.org/peps/rev/4de91c027ae2 changeset: 4969:4de91c027ae2 user: Victor Stinner date: Mon Jul 01 22:29:08 2013 +0200 summary: PEP 445: cleanup Avoid "should", "may" and "might". Rephrase some sentences files: pep-0445.txt | 218 ++++++++++++++++++++------------------ 1 files changed, 114 insertions(+), 104 deletions(-) diff --git a/pep-0445.txt b/pep-0445.txt --- a/pep-0445.txt +++ b/pep-0445.txt @@ -12,7 +12,8 @@ Abstract ======== -Add new APIs to customize Python memory allocators. +Add new Application Programming Interfaces (API) to customize Python +memory allocators. Rationale @@ -20,21 +21,22 @@ Use cases: -* Application embedding Python may want to isolate Python memory from - the memory of the application, or may want to use a different memory +* Applications embedding Python which want to isolate Python memory from + the memory of the application, or want to use a different memory allocator optimized for its Python usage * Python running on embedded devices with low memory and slow CPU. - A custom memory allocator may be required to use efficiently the - memory and/or to be able to use all the memory of the device. -* Debug tool to: + A custom memory allocator can be used for efficiency and/or to get + access all the memory of the device. +* Debug tools for memory allocators: - - track the memory usage (memory leaks) - - get the Python filename and line number where an object was - allocated - - detect buffer underflow, buffer overflow and detect misuse of Python - allocator APIs (builtin Python debug hooks) - - force allocation to fail to test handling of ``MemoryError`` - exception + - track the memory usage (find memory leaks) + - get the location of a memory allocation: Python filename and line + number, and the size of a memory block + - detect buffer underflow, buffer overflow and misuse of Python + allocator APIs (see `Redesign Debug Checks on Memory Block + Allocators as Hooks`_) + - force memory allocations to fail to test handling of the + ``MemoryError`` exception Proposal @@ -56,8 +58,7 @@ * Add a new ``PyMemAllocator`` structure:: typedef struct { - /* user context passed as the first argument - to the 3 functions */ + /* user context passed as the first argument to the 3 functions */ void *ctx; /* allocate a memory block */ @@ -82,7 +83,7 @@ - ``PYMEM_DOMAIN_OBJ``: ``PyObject_Malloc()``, ``PyObject_Realloc()`` and ``PyObject_Free()`` -* Add new functions to get and set memory allocators: +* Add new functions to get and set memory block allocators: - ``void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)`` - ``void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)`` @@ -94,8 +95,7 @@ * Add a new ``PyObjectArenaAllocator`` structure:: typedef struct { - /* user context passed as the first argument - to the 2 functions */ + /* user context passed as the first argument to the 2 functions */ void *ctx; /* allocate an arena */ @@ -111,18 +111,17 @@ - ``void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)`` - ``void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)`` -* Add a new function to setup the debug checks on memory allocators when - a memory allocator is replaced: +* Add a new function to reinstall the debug checks on memory allocators when + a memory allocator is replaced with ``PyMem_SetAllocator()``: - ``void PyMem_SetupDebugHooks(void)`` - - Install the debug hook on all memory block allocators. The function - can be called more than once, hooks are not reinstalled if they - were already installed. - - The function does nothing is Python is not compiled in debug mode + - Install the debug hooks on all memory block allocators. The function can be + called more than once, hooks are only installed once. + - The function does nothing is Python is not compiled in debug mode. -* Memory allocators always returns *NULL* if size is greater than - ``PY_SSIZE_T_MAX``. The check is done before calling the - inner function. +* Memory block allocators always return *NULL* if *size* is greater than + ``PY_SSIZE_T_MAX``. The check is done before calling the inner + function. The *pymalloc* allocator is optimized for objects smaller than 512 bytes with a short lifetime. It uses memory mappings with a fixed size of 256 @@ -140,8 +139,8 @@ and ``free()`` -Redesign Debug Checks on Memory Allocators as Hooks ----------------------------------------------------- +Redesign Debug Checks on Memory Block Allocators as Hooks +--------------------------------------------------------- Since Python 2.3, Python implements different checks on memory allocators in debug mode: @@ -157,7 +156,8 @@ ``PyMem_Realloc()``, ``PyMem_Free()``, ``PyObject_Malloc()``, ``PyObject_Realloc()`` and ``PyObject_Free()`` using macros. The new allocator allocates a larger buffer and write a pattern to detect buffer -underflow and overflow. It uses the original ``PyObject_Malloc()`` +underflow, buffer overflow and use after free (fill the buffer with the +pattern ``0xDB``). It uses the original ``PyObject_Malloc()`` function to allocate memory. So ``PyMem_Malloc()`` and ``PyMem_Realloc()`` call indirectly ``PyObject_Malloc()`` and ``PyObject_Realloc()``. @@ -178,13 +178,14 @@ * ``PyObject_Free()`` => ``_PyMem_DebugFree()`` => ``_PyObject_Free()`` -As a result, ``PyMem_Malloc()`` and ``PyMem_Realloc()`` now always call -``malloc()`` and ``realloc()``, instead of calling ``PyObject_Malloc()`` -and ``PyObject_Realloc()`` in debug mode. +As a result, ``PyMem_Malloc()`` and ``PyMem_Realloc()`` now call +``malloc()`` and ``realloc()`` in release mode and in debug mode, +instead of calling ``PyObject_Malloc()`` and ``PyObject_Realloc()`` in +debug mode. When at least one memory allocator is replaced with ``PyMem_SetAllocator()``, the ``PyMem_SetupDebugHooks()`` function must -be called to install the debug hooks on top on the new allocator. +be called to reinstall the debug hooks on top on the new allocator. Don't call malloc() directly anymore @@ -195,7 +196,7 @@ ``PyObject_Realloc()`` falls back on ``PyMem_Realloc()`` instead of ``realloc()`` -Replace direct calls to ``malloc()`` with ``PyMem_Malloc()``, or +Direct calls to ``malloc()`` are replaced with ``PyMem_Malloc()``, or ``PyMem_RawMalloc()`` if the GIL is not held. Configure external libraries like zlib or OpenSSL to allocate memory @@ -205,22 +206,22 @@ For the "track memory usage" use case, it is important to track memory allocated in external libraries to have accurate reports, because these -allocations may be large. +allocations can be large (can raise a ``MemoryError`` exception). If an hook is used to the track memory usage, the memory allocated by -``malloc()`` will not be tracked. Remaining ``malloc()`` in external -libraries like OpenSSL or bz2 may allocate large memory blocks and so -would be missed in memory usage reports. +direct calls to ``malloc()`` will not be tracked. Remaining ``malloc()`` +in external libraries like OpenSSL or bz2 can allocate large memory +blocks and so would be missed in memory usage reports. Examples ======== -Use case 1: Replace Memory Allocator, keep pymalloc +Use case 1: Replace Memory Allocators, keep pymalloc ---------------------------------------------------- Dummy example wasting 2 bytes per memory block, -and 10 bytes per memory mapping:: +and 10 bytes per *pymalloc* arena:: #include @@ -267,6 +268,7 @@ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); + /* leave PYMEM_DOMAIN_OBJ unchanged, use pymalloc */ arena.ctx = &arena_padding; arena.alloc = my_alloc_arena; @@ -277,7 +279,7 @@ } -Use case 2: Replace Memory Allocator, override pymalloc +Use case 2: Replace Memory Allocators, override pymalloc -------------------------------------------------------- If your allocator is optimized for allocations of objects smaller than @@ -322,11 +324,14 @@ PyMem_SetupDebugHooks(); } +The *pymalloc* arena does not need to be replaced, because it is no more +used by the new allocator. -Use case 3: Setup Allocator Hooks ---------------------------------- -Example to setup hooks on all memory allocators:: +Use case 3: Setup Hooks On Memory Block Allocators +-------------------------------------------------- + +Example to setup hooks on all memory block allocators:: struct { PyMemAllocator raw; @@ -390,22 +395,23 @@ } .. note:: - ``PyMem_SetupDebugHooks()`` does not need to be called because the - allocator is not replaced: Python debug hooks are installed - automatically at startup. + ``PyMem_SetupDebugHooks()`` does not need to be called because + memory allocator are not replaced: the debug checks on memory + block allocators are installed automatically at startup. Performances ============ +The implementation of this PEP (issue #3329) has no visible overhead on +the Python benchmark suite. + Results of the `Python benchmarks suite `_ (-b 2n3): some tests are 1.04x -faster, some tests are 1.04 slower, significant is between 115 and -191. +faster, some tests are 1.04 slower. Results of pybench microbenchmark: +"+0.1%" slower globally (diff between -4.9% and +5.6%). -Results of pybench benchmark: "+0.1%" slower globally (diff between --4.9% and +5.6%). - -The full reports are attached to the issue #3329. +The full output of benchmarks is attached to the issue #3329. Rejected Alternatives @@ -428,8 +434,9 @@ * ``void PyMem_SetAllocator(PyMemAllocator *allocator)`` * ``void PyObject_SetAllocator(PyMemAllocator *allocator)`` -With more specific functions, it becomes more difficult to write generic -code, like reusing the same code for different allocator domains. +This alternative was rejected because it is not possible to write +generic code with more specific functions: code must be duplicated for +each memory allocator domain. Make PyMem_Malloc() reuse PyMem_RawMalloc() by default @@ -439,25 +446,25 @@ calling ``PyMem_SetAllocator(PYMEM_DOMAIN_RAW, alloc)`` would also also patch ``PyMem_Malloc()`` indirectly. -This option was rejected because ``PyMem_SetAllocator()`` would have a -different behaviour depending on the domain. Always having the same -behaviour is less error-prone. +This alternative was rejected because ``PyMem_SetAllocator()`` would +have a different behaviour depending on the domain. Always having the +same behaviour is less error-prone. Add a new PYDEBUGMALLOC environment variable -------------------------------------------- -To be able to use the Python builtin debug hooks even when a custom -memory allocator replaces the default Python allocator, an environment -variable ``PYDEBUGMALLOC`` can be added to setup these debug function -hooks, instead of adding the new function ``PyMem_SetupDebugHooks()``. -If the environment variable is present, ``PyMem_SetRawAllocator()``, -``PyMem_SetAllocator()`` and ``PyObject_SetAllocator()`` will reinstall -automatically the hook on top of the new allocator. +Add a new ``PYDEBUGMALLOC`` environment variable to enable debug checks +on memory block allocators. The environment variable replaces the new +function ``PyMem_SetupDebugHooks()`` which is not needed anymore. +Another advantage is to allow to enable debug checks even in release +mode: debug checks are always compiled, but only enabled when the +environment variable is present and non-empty. -A new environment variable would make the Python initialization even -more complex. The `PEP 432 `_ -tries to simply the CPython startup sequence. +This alternative was rejected because a new environment variable would +make the Python initialization even more complex. The `PEP 432 +`_ tries to simply the CPython +startup sequence. Use macros to get customizable allocators @@ -503,7 +510,7 @@ void* _PyMem_MallocTrace(const char *filename, int lineno, size_t size); - /* need also a function for the Python stable ABI */ + /* the function is still needed for the Python stable ABI */ void* PyMem_Malloc(size_t size); #define PyMem_Malloc(size) \ @@ -527,19 +534,19 @@ calls indirectly ``PyObject_Malloc()`` which requires the GIL to be held. That's why ``PyMem_Malloc()`` must be called with the GIL held. -This PEP proposes changes ``PyMem_Malloc()``: it now always call -``malloc()``. The "GIL must be held" restriction can be removed from +This PEP changes ``PyMem_Malloc()``: it now always call ``malloc()``. +The "GIL must be held" restriction could be removed from ``PyMem_Malloc()``. This alternative was rejected because allowing to call -``PyMem_Malloc()`` without holding the GIL might break applications +``PyMem_Malloc()`` without holding the GIL can break applications which setup their own allocators or allocator hooks. Holding the GIL is convinient to develop a custom allocator: no need to care of other threads. It is also convinient for a debug allocator hook: Python internal objects can be safetly inspected. Calling ``PyGILState_Ensure()`` in -a memory allocator may have unexpected behaviour, especially at Python +a memory allocator has unexpected behaviour, especially at Python startup and at creation of a new Python thread state. @@ -552,13 +559,14 @@ The ``PyMem_Malloc()`` is used without the GIL held in some Python functions. For example, the ``main()`` and ``Py_Main()`` functions of Python call ``PyMem_Malloc()`` whereas the GIL do not exist yet. In this -case, ``PyMem_Malloc()`` should be replaced with ``malloc()`` (or +case, ``PyMem_Malloc()`` would be replaced with ``malloc()`` (or ``PyMem_RawMalloc()``). -If an hook is used to the track memory usage, the memory allocated by -direct calls to ``malloc()`` will not be tracked. External libraries -like OpenSSL or bz2 should not call ``malloc()`` directly, so large -allocated will be included in memory usage reports. +This alternative was rejected because ``PyMem_RawMalloc()`` is required +for accurate reports of the memory usage. When a debug hook is used to +track the memory usage, the memory allocated by direct calls to +``malloc()`` cannot be tracked. ``PyMem_RawMalloc()`` can be hooked and +so all the memory allocated by Python can be tracked. Use existing debug tools to analyze the memory @@ -571,11 +579,11 @@ `_, etc. The problem is to retrieve the Python object related to a memory pointer -to read its type and/or content. Another issue is to retrieve the +to read its type and/or its content. Another issue is to retrieve the location of the memory allocation: the C backtrace is usually useless -(same reasoning than macros using ``__FILE__`` and ``__LINE__``), the -Python filename and line number (or even the Python traceback) is more -useful. +(same reasoning than macros using ``__FILE__`` and ``__LINE__``, see +`Pass the C filename and line number`_), the Python filename and line +number (or even the Python traceback) is more useful. This alternative was rejected because classic tools are unable to introspect Python internals to collect such information. Being able to @@ -586,8 +594,8 @@ Add a msize() function ---------------------- -Add another field to ``PyMemAllocator`` and ``PyObjectArenaAllocator`` -structures:: +Add another function to ``PyMemAllocator`` and +``PyObjectArenaAllocator`` structures:: size_t msize(void *ptr); @@ -607,8 +615,8 @@ platforms implement it. For example, Linux with the GNU libc does not provide a function to get the size of a memory block. ``msize()`` is not currently used in the Python source code. The function is only used to -track the memory usage, but makes the API more complex. A debug hook can -implemente the function internally, there is no need to add it to +track the memory usage, and makes the API more complex. A debug hook can +implement the function internally, there is no need to add it to ``PyMemAllocator`` and ``PyObjectArenaAllocator`` structures. @@ -653,17 +661,19 @@ * lzma: `LZMA SDK - How to Use `_, pass an opaque pointer -* lipmpdec doesn't have this extra *ctx* parameter +* lipmpdec: no opaque pointer (classic malloc API) Other libraries: * glib: `g_mem_set_vtable() `_ -* libxml2: `xmlGcMemSetup() `_, +* libxml2: + `xmlGcMemSetup() `_, global * Oracle's OCI: `Oracle Call Interface Programmer's Guide, Release 2 (9.2) - `_ + `_, + pass an opaque pointer See also the `GNU libc: Memory Allocation Hooks `_. @@ -676,30 +686,30 @@ Its implementation depends on the platform and of the C library. The GNU C library uses a modified ptmalloc2, based on "Doug Lea's Malloc" (dlmalloc). FreeBSD uses `jemalloc -`_. Google provides tcmalloc which +`_. Google provides *tcmalloc* which is part of `gperftools `_. ``malloc()`` uses two kinds of memory: heap and memory mappings. Memory mappings are usually used for large allocations (ex: larger than 256 KB), whereas the heap is used for small allocations. -On UNIX, the heap is handled by ``brk()`` and ``sbrk()`` system calls on -Linux, and it is contiguous. On Windows, the heap is handled by -``HeapAlloc()`` and may be discontiguous. Memory mappings are handled by -``mmap()`` on UNIX and ``VirtualAlloc()`` on Windows, they may be +On UNIX, the heap is handled by ``brk()`` and ``sbrk()`` system calls, +and it is contiguous. On Windows, the heap is handled by +``HeapAlloc()`` and can be discontiguous. Memory mappings are handled by +``mmap()`` on UNIX and ``VirtualAlloc()`` on Windows, they can be discontiguous. Releasing a memory mapping gives back immediatly the memory to the -system. On UNIX, heap memory is only given back to the system if it is -at the end of the heap. Otherwise, the memory will only be given back to -the system when all the memory located after the released memory are -also released. +system. On UNIX, the heap memory is only given back to the system if the +released block is located at the end of the heap. Otherwise, the memory +will only be given back to the system when all the memory located after +the released memory is also released. -To allocate memory in the heap, the allocator tries to reuse free space. -If there is no contiguous space big enough, the heap must be increased, -even if we have more free space than required size. This issue is +To allocate memory on the heap, an allocator tries to reuse free space. +If there is no contiguous space big enough, the heap must be enlarged, +even if there is more free space than required size. This issue is called the "memory fragmentation": the memory usage seen by the system -may be much higher than real usage. On Windows, ``HeapAlloc()`` creates +is higher than real usage. On Windows, ``HeapAlloc()`` creates a new memory mapping with ``VirtualAlloc()`` if there is not enough free contiguous memory. @@ -730,8 +740,8 @@ `_ * `Issue #13483: Use VirtualAlloc to allocate memory arenas `_ -* `Issue #16742: PyOS_Readline drops GIL and calls PyOS_StdioReadline, which - isn't thread safe `_ +* `Issue #16742: PyOS_Readline drops GIL and calls PyOS_StdioReadline, + which isn't thread safe `_ * `Issue #18203: Replace calls to malloc() with PyMem_Malloc() or PyMem_RawMalloc() `_ * `Issue #18227: Use Python memory allocators in external libraries like -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 1 22:45:04 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 1 Jul 2013 22:45:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_445=3A_rephrase_abstract?= Message-ID: <3bkgZ86Lxyz7Ll3@mail.python.org> http://hg.python.org/peps/rev/f3032259c28e changeset: 4970:f3032259c28e user: Victor Stinner date: Mon Jul 01 22:44:48 2013 +0200 summary: PEP 445: rephrase abstract Remove also a wrong sentence: using the same prototypes than external libraries is not a must-have. In fact, it was neither a guideline for this PEP, but just an inspiration. files: pep-0445.txt | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pep-0445.txt b/pep-0445.txt --- a/pep-0445.txt +++ b/pep-0445.txt @@ -12,8 +12,8 @@ Abstract ======== -Add new Application Programming Interfaces (API) to customize Python -memory allocators. +This PEP proposes new Application Programming Interfaces (API) to customize +Python memory allocators. Rationale @@ -642,9 +642,6 @@ External libraries ================== -Python should try to reuse the same prototypes for allocator functions -than other libraries. - Libraries used by Python: * OpenSSL: `CRYPTO_set_mem_functions() -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 1 23:00:33 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 1 Jul 2013 23:00:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzM5?= =?utf-8?q?=3A_use_with_self=2EassertRaises=28=29_to_make_test_case_more_r?= =?utf-8?q?eadable?= Message-ID: <3bkgw171JqzPPY@mail.python.org> http://hg.python.org/cpython/rev/fa0a03afe359 changeset: 84416:fa0a03afe359 branch: 3.3 parent: 84414:3ec5267f51ff user: Christian Heimes date: Mon Jul 01 23:00:13 2013 +0200 summary: Issue #18339: use with self.assertRaises() to make test case more readable files: Lib/test/test_pickle.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -117,9 +117,11 @@ def test_issue18339(self): unpickler = self.unpickler_class(io.BytesIO()) - self.assertRaises(TypeError, setattr, unpickler, "memo", object) + with self.assertRaises(TypeError): + unpickler.memo = object # used to cause a segfault - self.assertRaises(ValueError, setattr, unpickler, "memo", {-1: None}) + with self.assertRaises(ValueError): + unpickler.memo = {-1: None} unpickler.memo = {1: None} class CDispatchTableTests(AbstractDispatchTableTests): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 23:00:35 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 1 Jul 2013 23:00:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318339=3A_use_with_self=2EassertRaises=28=29_to_?= =?utf-8?q?make_test_case_more_readable?= Message-ID: <3bkgw31j8nz7Lkq@mail.python.org> http://hg.python.org/cpython/rev/de44cd866bb0 changeset: 84417:de44cd866bb0 parent: 84415:035577781505 parent: 84416:fa0a03afe359 user: Christian Heimes date: Mon Jul 01 23:00:22 2013 +0200 summary: Issue #18339: use with self.assertRaises() to make test case more readable files: Lib/test/test_pickle.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -117,9 +117,11 @@ def test_issue18339(self): unpickler = self.unpickler_class(io.BytesIO()) - self.assertRaises(TypeError, setattr, unpickler, "memo", object) + with self.assertRaises(TypeError): + unpickler.memo = object # used to cause a segfault - self.assertRaises(ValueError, setattr, unpickler, "memo", {-1: None}) + with self.assertRaises(ValueError): + unpickler.memo = {-1: None} unpickler.memo = {1: None} class CDispatchTableTests(AbstractDispatchTableTests): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 23:15:59 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 1 Jul 2013 23:15:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_445=3A_explain_why_Extern?= =?utf-8?q?al_Libraries_and_Memory_Allocators_sections_are?= Message-ID: <3bkhFq2lJ8z7Ll8@mail.python.org> http://hg.python.org/peps/rev/358aa763611a changeset: 4971:358aa763611a user: Victor Stinner date: Mon Jul 01 23:15:45 2013 +0200 summary: PEP 445: explain why External Libraries and Memory Allocators sections are present files: pep-0445.txt | 16 +++++++++++++--- 1 files changed, 13 insertions(+), 3 deletions(-) diff --git a/pep-0445.txt b/pep-0445.txt --- a/pep-0445.txt +++ b/pep-0445.txt @@ -639,9 +639,11 @@ In C++, the context can be used to pass *this*. -External libraries +External Libraries ================== +Examples of API used to customize memory allocators. + Libraries used by Python: * OpenSSL: `CRYPTO_set_mem_functions() @@ -672,11 +674,15 @@ `_, pass an opaque pointer +The new *ctx* parameter of this PEP was inspired by the API of zlib and +Oracle's OCI libraries. + See also the `GNU libc: Memory Allocation Hooks -`_. +`_ +which uses a different approach to hook memory allocators. -Memory allocators +Memory Allocators ================= The C standard library provides the well known ``malloc()`` function. @@ -727,6 +733,10 @@ `_: efficient way to allocate groups of equal-sized chunks of memory +This PEP permits to choose exactly which memory allocator is used for your +application depending on its usage of the memory (number of allocation, size of +allocations, lifetime of objects, etc.). + Links ===== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 1 23:43:20 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 1 Jul 2013 23:43:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzI4?= =?utf-8?q?=3A_Reorder_ops_in_PyThreadState=5FDelete*=28=29_functions=2E_N?= =?utf-8?q?ow_the?= Message-ID: <3bkhsN24yzz7LlT@mail.python.org> http://hg.python.org/cpython/rev/ff30bf84b378 changeset: 84418:ff30bf84b378 branch: 3.3 parent: 84416:fa0a03afe359 user: Christian Heimes date: Mon Jul 01 23:42:28 2013 +0200 summary: Issue #18328: Reorder ops in PyThreadState_Delete*() functions. Now the tstate is first removed from TLS and then deallocated. CID 1019639 (#1 of 1): Use after free (USE_AFTER_FREE) use_after_free: Using freed pointer tstate. files: Misc/NEWS | 3 +++ Python/pystate.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #18328: Reorder ops in PyThreadState_Delete*() functions. Now the + tstate is first removed from TLS and then deallocated. + - Issue #18184: PyUnicode_FromFormat() and PyUnicode_FromFormatV() now raise OverflowError when an argument of %c format is out of range. diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -388,11 +388,11 @@ { if (tstate == _Py_atomic_load_relaxed(&_PyThreadState_Current)) Py_FatalError("PyThreadState_Delete: tstate is still current"); - tstate_delete_common(tstate); #ifdef WITH_THREAD if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) PyThread_delete_key_value(autoTLSkey); #endif /* WITH_THREAD */ + tstate_delete_common(tstate); } @@ -406,9 +406,9 @@ Py_FatalError( "PyThreadState_DeleteCurrent: no current tstate"); _Py_atomic_store_relaxed(&_PyThreadState_Current, NULL); - tstate_delete_common(tstate); if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) PyThread_delete_key_value(autoTLSkey); + tstate_delete_common(tstate); PyEval_ReleaseLock(); } #endif /* WITH_THREAD */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 1 23:43:21 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 1 Jul 2013 23:43:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318328=3A_Reorder_ops_in_PyThreadState=5FDelete*?= =?utf-8?q?=28=29_functions=2E_Now_the?= Message-ID: <3bkhsP48V2z7LlQ@mail.python.org> http://hg.python.org/cpython/rev/ebe064e542ef changeset: 84419:ebe064e542ef parent: 84417:de44cd866bb0 parent: 84418:ff30bf84b378 user: Christian Heimes date: Mon Jul 01 23:43:09 2013 +0200 summary: Issue #18328: Reorder ops in PyThreadState_Delete*() functions. Now the tstate is first removed from TLS and then deallocated. CID 1019639 (#1 of 1): Use after free (USE_AFTER_FREE) use_after_free: Using freed pointer tstate. files: Misc/NEWS | 3 +++ Python/pystate.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18328: Reorder ops in PyThreadState_Delete*() functions. Now the + tstate is first removed from TLS and then deallocated. + - Issue #13483: Use VirtualAlloc in obmalloc on Windows. - Issue #18184: PyUnicode_FromFormat() and PyUnicode_FromFormatV() now raise diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -374,11 +374,11 @@ { if (tstate == _Py_atomic_load_relaxed(&_PyThreadState_Current)) Py_FatalError("PyThreadState_Delete: tstate is still current"); - tstate_delete_common(tstate); #ifdef WITH_THREAD if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) PyThread_delete_key_value(autoTLSkey); #endif /* WITH_THREAD */ + tstate_delete_common(tstate); } @@ -392,9 +392,9 @@ Py_FatalError( "PyThreadState_DeleteCurrent: no current tstate"); _Py_atomic_store_relaxed(&_PyThreadState_Current, NULL); - tstate_delete_common(tstate); if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) PyThread_delete_key_value(autoTLSkey); + tstate_delete_common(tstate); PyEval_ReleaseLock(); } #endif /* WITH_THREAD */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 00:17:42 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 2 Jul 2013 00:17:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzQz?= =?utf-8?q?=3A_faulthandler=2Eregister=28=29_now_keeps_the_previous_signal?= =?utf-8?q?_handler?= Message-ID: <3bkjd214Fqz7LlC@mail.python.org> http://hg.python.org/cpython/rev/229dde749ed6 changeset: 84420:229dde749ed6 branch: 3.3 parent: 84418:ff30bf84b378 user: Victor Stinner date: Tue Jul 02 00:14:56 2013 +0200 summary: Issue #18343: faulthandler.register() now keeps the previous signal handler when the function is called twice, so faulthandler.unregister() restores correctly the original signal handler. files: Misc/NEWS | 4 ++++ Modules/faulthandler.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -41,6 +41,10 @@ Library ------- +- Issue #18343: faulthandler.register() now keeps the previous signal handler + when the function is called twice, so faulthandler.unregister() restores + correctly the original signal handler. + - Issue #17097: Make multiprocessing ignore EINTR. - Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -742,6 +742,8 @@ PyErr_SetFromErrno(PyExc_OSError); return NULL; } + + user->previous = previous; } Py_XDECREF(user->file); @@ -750,7 +752,6 @@ user->fd = fd; user->all_threads = all_threads; user->chain = chain; - user->previous = previous; user->interp = tstate->interp; user->enabled = 1; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 00:17:43 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 2 Jul 2013 00:17:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_Issue_=2318343=3A_faulthandler=2Eregis?= =?utf-8?q?ter=28=29_now_keeps_the_previous_signal?= Message-ID: <3bkjd3369bz7LlT@mail.python.org> http://hg.python.org/cpython/rev/74b7ff20e0e4 changeset: 84421:74b7ff20e0e4 parent: 84419:ebe064e542ef parent: 84420:229dde749ed6 user: Victor Stinner date: Tue Jul 02 00:17:14 2013 +0200 summary: (Merge 3.3) Issue #18343: faulthandler.register() now keeps the previous signal handler when the function is called twice, so faulthandler.unregister() restores correctly the original signal handler. files: Misc/NEWS | 4 ++++ Modules/faulthandler.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -138,6 +138,10 @@ Library ------- +- Issue #18343: faulthandler.register() now keeps the previous signal handler + when the function is called twice, so faulthandler.unregister() restores + correctly the original signal handler. + - Issue #17097: Make multiprocessing ignore EINTR. - Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -741,6 +741,8 @@ PyErr_SetFromErrno(PyExc_OSError); return NULL; } + + user->previous = previous; } Py_XDECREF(user->file); @@ -749,7 +751,6 @@ user->fd = fd; user->all_threads = all_threads; user->chain = chain; - user->previous = previous; user->interp = tstate->interp; user->enabled = 1; -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jul 2 05:46:19 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 02 Jul 2013 05:46:19 +0200 Subject: [Python-checkins] Daily reference leaks (74b7ff20e0e4): sum=0 Message-ID: results for 74b7ff20e0e4 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogheinsp', '-x'] From python-checkins at python.org Tue Jul 2 13:42:33 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 2 Jul 2013 13:42:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3Mjcz?= =?utf-8?q?=3A_Clarify_that_pool_methods_can_only_be_used_by_parent_proces?= =?utf-8?q?s=2E?= Message-ID: <3bl3Tj23zyz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/389788ba6bcb changeset: 84422:389788ba6bcb branch: 2.7 parent: 84413:bc34fe4a0d58 user: Richard Oudkerk date: Tue Jul 02 12:31:50 2013 +0100 summary: Issue #17273: Clarify that pool methods can only be used by parent process. files: Doc/library/multiprocessing.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -287,6 +287,9 @@ print result.get(timeout=1) # prints "100" unless your computer is *very* slow print pool.map(f, range(10)) # prints "[0, 1, 4,..., 81]" +Note that the methods of a pool should only ever be used by the +process which created it. + Reference --------- @@ -1599,6 +1602,9 @@ *initializer* is not ``None`` then each worker process will call ``initializer(*initargs)`` when it starts. + Note that the methods of the pool object should only be called by + the process which created the pool. + .. versionadded:: 2.7 *maxtasksperchild* is the number of tasks a worker process can complete before it will exit and be replaced with a fresh worker process, to enable -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 13:42:34 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 2 Jul 2013 13:42:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3Mjcz?= =?utf-8?q?=3A_Clarify_that_pool_methods_can_only_be_used_by_parent_proces?= =?utf-8?q?s=2E?= Message-ID: <3bl3Tk48p6z7Ljk@mail.python.org> http://hg.python.org/cpython/rev/57fe80fda9be changeset: 84423:57fe80fda9be branch: 3.3 parent: 84420:229dde749ed6 user: Richard Oudkerk date: Tue Jul 02 12:32:00 2013 +0100 summary: Issue #17273: Clarify that pool methods can only be used by parent process. files: Doc/library/multiprocessing.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -284,6 +284,9 @@ print(result.get(timeout=1)) # prints "100" unless your computer is *very* slow print(pool.map(f, range(10))) # prints "[0, 1, 4,..., 81]" +Note that the methods of a pool should only ever be used by the +process which created it. + Reference --------- @@ -1665,6 +1668,9 @@ *initializer* is not ``None`` then each worker process will call ``initializer(*initargs)`` when it starts. + Note that the methods of the pool object should only be called by + the process which created the pool. + .. versionadded:: 3.2 *maxtasksperchild* is the number of tasks a worker process can complete before it will exit and be replaced with a fresh worker process, to enable -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 13:42:35 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 2 Jul 2013 13:42:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317273=3A_Clarify_that_pool_methods_can_only_be_?= =?utf-8?q?used_by_parent_process=2E?= Message-ID: <3bl3Tl69hcz7Lkw@mail.python.org> http://hg.python.org/cpython/rev/7ccf3d36ad13 changeset: 84424:7ccf3d36ad13 parent: 84421:74b7ff20e0e4 parent: 84423:57fe80fda9be user: Richard Oudkerk date: Tue Jul 02 12:41:00 2013 +0100 summary: Issue #17273: Clarify that pool methods can only be used by parent process. files: Doc/library/multiprocessing.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -284,6 +284,9 @@ print(result.get(timeout=1)) # prints "100" unless your computer is *very* slow print(pool.map(f, range(10))) # prints "[0, 1, 4,..., 81]" +Note that the methods of a pool should only ever be used by the +process which created it. + Reference --------- @@ -1668,6 +1671,9 @@ *initializer* is not ``None`` then each worker process will call ``initializer(*initargs)`` when it starts. + Note that the methods of the pool object should only be called by + the process which created the pool. + .. versionadded:: 3.2 *maxtasksperchild* is the number of tasks a worker process can complete before it will exit and be replaced with a fresh worker process, to enable -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 14:02:32 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 2 Jul 2013 14:02:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0MjA2?= =?utf-8?q?=3A_Clarify_docs_for_Queue=2Ejoin=5Fcancel=5Fthread=28=29=2E?= Message-ID: <3bl3wm34bxz7LlR@mail.python.org> http://hg.python.org/cpython/rev/f35401dba89f changeset: 84425:f35401dba89f branch: 2.7 parent: 84422:389788ba6bcb user: Richard Oudkerk date: Tue Jul 02 12:58:21 2013 +0100 summary: Issue #14206: Clarify docs for Queue.join_cancel_thread(). files: Doc/library/multiprocessing.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -630,6 +630,13 @@ the background thread from being joined automatically when the process exits -- see :meth:`join_thread`. + A better name for this method might be + ``allow_exit_without_flush()``. It is likely to cause enqueued + data to lost, and you almost certainly will not need to use it. + It is really only there if you need the current process to exit + immediately without waiting to flush enqueued data to the + underlying pipe, and you don't care about lost data. + .. class:: multiprocessing.queues.SimpleQueue() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 14:02:33 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 2 Jul 2013 14:02:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE0MjA2?= =?utf-8?q?=3A_Clarify_docs_for_Queue=2Ejoin=5Fcancel=5Fthread=28=29=2E?= Message-ID: <3bl3wn4yvVz7LlT@mail.python.org> http://hg.python.org/cpython/rev/9746f217a270 changeset: 84426:9746f217a270 branch: 3.3 parent: 84423:57fe80fda9be user: Richard Oudkerk date: Tue Jul 02 12:59:55 2013 +0100 summary: Issue #14206: Clarify docs for Queue.join_cancel_thread(). files: Doc/library/multiprocessing.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -659,6 +659,13 @@ the background thread from being joined automatically when the process exits -- see :meth:`join_thread`. + A better name for this method might be + ``allow_exit_without_flush()``. It is likely to cause enqueued + data to lost, and you almost certainly will not need to use it. + It is really only there if you need the current process to exit + immediately without waiting to flush enqueued data to the + underlying pipe, and you don't care about lost data. + .. class:: SimpleQueue() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 14:02:34 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 2 Jul 2013 14:02:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2314206=3A_Clarify_docs_for_Queue=2Ejoin=5Fcancel?= =?utf-8?b?X3RocmVhZCgpLg==?= Message-ID: <3bl3wp6wS5z7LlT@mail.python.org> http://hg.python.org/cpython/rev/d0b48efac9de changeset: 84427:d0b48efac9de parent: 84424:7ccf3d36ad13 parent: 84426:9746f217a270 user: Richard Oudkerk date: Tue Jul 02 13:01:31 2013 +0100 summary: Issue #14206: Clarify docs for Queue.join_cancel_thread(). files: Doc/library/multiprocessing.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -659,6 +659,13 @@ the background thread from being joined automatically when the process exits -- see :meth:`join_thread`. + A better name for this method might be + ``allow_exit_without_flush()``. It is likely to cause enqueued + data to lost, and you almost certainly will not need to use it. + It is really only there if you need the current process to exit + immediately without waiting to flush enqueued data to the + underlying pipe, and you don't care about lost data. + .. class:: SimpleQueue() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 14:41:05 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 2 Jul 2013 14:41:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3MjYx?= =?utf-8?q?=3A_Ensure_multiprocessing=27s_proxies_use_proper_address=2E?= Message-ID: <3bl4nF2VCszS2M@mail.python.org> http://hg.python.org/cpython/rev/20b59fec1123 changeset: 84428:20b59fec1123 branch: 2.7 parent: 84425:f35401dba89f user: Richard Oudkerk date: Tue Jul 02 13:31:43 2013 +0100 summary: Issue #17261: Ensure multiprocessing's proxies use proper address. files: Lib/multiprocessing/managers.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -763,6 +763,7 @@ elif kind == '#PROXY': exposed, token = result proxytype = self._manager._registry[token.typeid][-1] + token.address = self._token.address proxy = proxytype( token, self._serializer, manager=self._manager, authkey=self._authkey, exposed=exposed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #17261: Ensure multiprocessing's proxies use proper address. + - Issue #17097: Make multiprocessing ignore EINTR. - Issue #18155: The csv module now correctly handles csv files that use -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 14:41:06 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 2 Jul 2013 14:41:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3MjYx?= =?utf-8?q?=3A_Ensure_multiprocessing=27s_proxies_use_proper_address=2E?= Message-ID: <3bl4nG4WX5z7Ll3@mail.python.org> http://hg.python.org/cpython/rev/be4b9e677187 changeset: 84429:be4b9e677187 branch: 3.3 parent: 84426:9746f217a270 user: Richard Oudkerk date: Tue Jul 02 13:37:43 2013 +0100 summary: Issue #17261: Ensure multiprocessing's proxies use proper address. files: Lib/multiprocessing/managers.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -731,6 +731,7 @@ elif kind == '#PROXY': exposed, token = result proxytype = self._manager._registry[token.typeid][-1] + token.address = self._token.address proxy = proxytype( token, self._serializer, manager=self._manager, authkey=self._authkey, exposed=exposed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -41,6 +41,8 @@ Library ------- +- Issue #17261: Ensure multiprocessing's proxies use proper address. + - Issue #18343: faulthandler.register() now keeps the previous signal handler when the function is called twice, so faulthandler.unregister() restores correctly the original signal handler. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 14:41:07 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 2 Jul 2013 14:41:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317261=3A_Ensure_multiprocessing=27s_proxies_use?= =?utf-8?q?_proper_address=2E?= Message-ID: <3bl4nH6ggFz7LlQ@mail.python.org> http://hg.python.org/cpython/rev/7387b884f833 changeset: 84430:7387b884f833 parent: 84427:d0b48efac9de parent: 84429:be4b9e677187 user: Richard Oudkerk date: Tue Jul 02 13:38:58 2013 +0100 summary: Issue #17261: Ensure multiprocessing's proxies use proper address. files: Lib/multiprocessing/managers.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -731,6 +731,7 @@ elif kind == '#PROXY': exposed, token = result proxytype = self._manager._registry[token.typeid][-1] + token.address = self._token.address proxy = proxytype( token, self._serializer, manager=self._manager, authkey=self._authkey, exposed=exposed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -138,6 +138,8 @@ Library ------- +- Issue #17261: Ensure multiprocessing's proxies use proper address. + - Issue #18343: faulthandler.register() now keeps the previous signal handler when the function is called twice, so faulthandler.unregister() restores correctly the original signal handler. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 14:46:02 2013 From: python-checkins at python.org (nick.coghlan) Date: Tue, 2 Jul 2013 14:46:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devinabox=3A_Tweak_a_few_things?= Message-ID: <3bl4ty1HgZzRk0@mail.python.org> http://hg.python.org/devinabox/rev/53a1f44a6219 changeset: 48:53a1f44a6219 user: Nick Coghlan date: Tue Jul 02 22:45:52 2013 +1000 summary: Tweak a few things files: .hgignore | 2 ++ README | 22 +++++++++++++++------- full_coverage.py | 13 ++++++++++--- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -5,6 +5,8 @@ cpython devguide peps +# Unversioned downloads +Visual C++ Express/vc_web.exe # Generated coverage_report original_coverage_report diff --git a/README b/README --- a/README +++ b/README @@ -26,6 +26,10 @@ get updates, sparing the probably taxed internet connection at the sprint from doing complete repository cloning. +If recreating from an old checkout ``hg purge --all`` in the individual +clones is a handy way to ensure old build artifacts have been removed. +You will need to enable the purge extension in ``~/.hgrc``. + Mercurial --------- @@ -104,15 +108,16 @@ 01. Build the CPython repository 02. Clone the repository from https://bitbucket.org/ned/coveragepy -03. Download Distribute from https://pypi.python.org/pypi/distribute -04. Unpack and build Distribute with Python 3 in the coveragepy repository -05. Symlink the ``distribute-N.N.N/build/lib/setuptools`` directory into - ``coveragepy`` -06. Symlink ``distribute-N.N.N/build/lib/pkg_resources.py`` into ``coveragepy`` +03. Clone setuptools from https://bitbucket.org/pypa/setuptools/ +04. Run ``python3 setup.py build`` in the ``setuptools`` directory +05. Run ``ln -s ../setuptools/build/lib/setuptools`` in the ``coveragepy`` + directory +06. Run ``ln -s ../setuptools/build/lib/pkg_resources.py`` in the + ``coveragepy`` directory 07. Run ``./cpython/python full_coverage.py build`` 08. Run ``./cpython/python full_coverage.py run`` 09. Run ``./cpython/python full_coverage.py html original_coverage_report`` -10. ``make distclean`` the CPython repository +10. Run ``hg purge --all`` in the CPython repository All these steps will generate a complete coverage report for the standard @@ -150,9 +155,12 @@ just simplifies this by having a single command subsume both the configure and build steps. It also uses reasonable defaults (e.g. all cores on the CPU). +(You may need to cd into the CPython directory and run ``make`` to get the +extension modules to build) + ``index.html`` -------------- An HTML file with links to the various pieces of documentation you built -previously and the helper scripts. \ No newline at end of file +previously and the helper scripts. diff --git a/full_coverage.py b/full_coverage.py --- a/full_coverage.py +++ b/full_coverage.py @@ -29,6 +29,13 @@ yield os.chdir(original_directory) +def make_setup_cmd(*args): + # Silence a spurious warning from setuptools + # See https://bitbucket.org/pypa/setuptools/issue/29/ + cmd = [sys.executable, '-W', 'ignore::UserWarning:distutils.dist', + 'setup.py'] + cmd.extend(args) + return cmd def build(args): """Build coverage.py's C-based tracer. @@ -43,11 +50,11 @@ os.unlink(tracer_path) except FileNotFoundError: pass - subprocess.check_call([sys.executable, 'setup.py', 'clean']) + subprocess.check_call(make_setup_cmd('clean')) env = os.environ.copy() env['CPPFLAGS'] = '-I {} -I {}'.format(CPYTHON, os.path.join(CPYTHON, 'Include')) - command = [sys.executable, 'setup.py', 'build_ext', '--inplace'] + command = make_setup_cmd('build_ext', '--inplace') process = subprocess.Popen(command, env=env) process.wait() @@ -124,4 +131,4 @@ help_args = ['-h'] if args.command: help_args.insert(0, args.command) - parser.parse_args(help_args) \ No newline at end of file + parser.parse_args(help_args) -- Repository URL: http://hg.python.org/devinabox From python-checkins at python.org Tue Jul 2 15:08:49 2013 From: python-checkins at python.org (eric.smith) Date: Tue, 2 Jul 2013 15:08:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogQ2xvc2VzICMxODMx?= =?utf-8?q?2=3A_=27make_distclean=27_no_longer_deletes_files_in_dot-direct?= =?utf-8?q?ories=2E?= Message-ID: <3bl5PF6xfVzS29@mail.python.org> http://hg.python.org/cpython/rev/5896f887a93a changeset: 84431:5896f887a93a branch: 2.7 parent: 84428:20b59fec1123 user: Eric V. Smith date: Tue Jul 02 09:02:03 2013 -0400 summary: Closes #18312: 'make distclean' no longer deletes files in dot-directories. files: Makefile.pre.in | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1295,11 +1295,11 @@ Modules/ld_so_aix Modules/python.exp Misc/python.pc -rm -f python*-gdb.py -rm -f pybuilddir.txt - find $(srcdir) '(' -name '*.fdc' -o -name '*~' \ - -o -name '[@,#]*' -o -name '*.old' \ - -o -name '*.orig' -o -name '*.rej' \ - -o -name '*.bak' ')' \ - -exec rm -f {} ';' + find $(srcdir)/[a-zA-Z]* '(' -name '*.fdc' -o -name '*~' \ + -o -name '[@,#]*' -o -name '*.old' \ + -o -name '*.orig' -o -name '*.rej' \ + -o -name '*.bak' ')' \ + -exec rm -f {} ';' # Check for smelly exported symbols (not starting with Py/_Py) smelly: all -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 15:08:51 2013 From: python-checkins at python.org (eric.smith) Date: Tue, 2 Jul 2013 15:08:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogQ2xvc2VzICMxODMx?= =?utf-8?q?2=3A_=27make_distclean=27_no_longer_deletes_files_in_dot-direct?= =?utf-8?q?ories=2E?= Message-ID: <3bl5PH1hJvzS2M@mail.python.org> http://hg.python.org/cpython/rev/910ec3471d55 changeset: 84432:910ec3471d55 branch: 3.3 parent: 84429:be4b9e677187 user: Eric V. Smith date: Tue Jul 02 09:06:54 2013 -0400 summary: Closes #18312: 'make distclean' no longer deletes files in dot-directories. files: Makefile.pre.in | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1413,11 +1413,11 @@ Modules/Setup Modules/Setup.local Modules/Setup.config \ Modules/ld_so_aix Modules/python.exp Misc/python.pc -rm -f python*-gdb.py - find $(srcdir) '(' -name '*.fdc' -o -name '*~' \ - -o -name '[@,#]*' -o -name '*.old' \ - -o -name '*.orig' -o -name '*.rej' \ - -o -name '*.bak' ')' \ - -exec rm -f {} ';' + find $(srcdir)/[a-zA-Z]* '(' -name '*.fdc' -o -name '*~' \ + -o -name '[@,#]*' -o -name '*.old' \ + -o -name '*.orig' -o -name '*.rej' \ + -o -name '*.bak' ')' \ + -exec rm -f {} ';' # Check for smelly exported symbols (not starting with Py/_Py) smelly: all -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 2 15:08:52 2013 From: python-checkins at python.org (eric.smith) Date: Tue, 2 Jul 2013 15:08:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE4MzEyOiBtZXJnZSBmcm9tIDMuMy4=?= Message-ID: <3bl5PJ3RpnzS8n@mail.python.org> http://hg.python.org/cpython/rev/8e838598eed1 changeset: 84433:8e838598eed1 parent: 84430:7387b884f833 parent: 84432:910ec3471d55 user: Eric V. Smith date: Tue Jul 02 09:07:53 2013 -0400 summary: #18312: merge from 3.3. files: Makefile.pre.in | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1416,11 +1416,11 @@ Modules/Setup Modules/Setup.local Modules/Setup.config \ Modules/ld_so_aix Modules/python.exp Misc/python.pc -rm -f python*-gdb.py - find $(srcdir) '(' -name '*.fdc' -o -name '*~' \ - -o -name '[@,#]*' -o -name '*.old' \ - -o -name '*.orig' -o -name '*.rej' \ - -o -name '*.bak' ')' \ - -exec rm -f {} ';' + find $(srcdir)/[a-zA-Z]* '(' -name '*.fdc' -o -name '*~' \ + -o -name '[@,#]*' -o -name '*.old' \ + -o -name '*.orig' -o -name '*.rej' \ + -o -name '*.bak' ')' \ + -exec rm -f {} ';' # Check for smelly exported symbols (not starting with Py/_Py) smelly: all -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 3 00:45:10 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 3 Jul 2013 00:45:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_445=3A_fix_typo?= Message-ID: <3blLBG3m3fzNyn@mail.python.org> http://hg.python.org/peps/rev/bd8e5c86fb27 changeset: 4972:bd8e5c86fb27 user: Victor Stinner date: Wed Jul 03 00:44:58 2013 +0200 summary: PEP 445: fix typo files: pep-0445.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0445.txt b/pep-0445.txt --- a/pep-0445.txt +++ b/pep-0445.txt @@ -134,7 +134,7 @@ bytes * ``PYMEM_DOMAIN_OBJ``: *pymalloc* allocator which falls back on ``PyMem_Malloc()`` for allocations larger than 512 bytes -* *pymalloc* arena allocator: ``VirualAlloc()`` and ``VirtualFree()`` on +* *pymalloc* arena allocator: ``VirtualAlloc()`` and ``VirtualFree()`` on Windows, ``mmap()`` and ``munmap()`` when available, or ``malloc()`` and ``free()`` -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Wed Jul 3 05:43:42 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 03 Jul 2013 05:43:42 +0200 Subject: [Python-checkins] Daily reference leaks (8e838598eed1): sum=0 Message-ID: results for 8e838598eed1 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogn4j0Cs', '-x'] From python-checkins at python.org Wed Jul 3 19:26:44 2013 From: python-checkins at python.org (barry.warsaw) Date: Wed, 3 Jul 2013 19:26:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Relax_PEP_8=27s_perceived_=28?= =?utf-8?q?but_incorrect=29_prohibition_against_backslashed=2E?= Message-ID: <3blq4N4v2PzRHr@mail.python.org> http://hg.python.org/peps/rev/98f42236d1af changeset: 4973:98f42236d1af user: Barry Warsaw date: Wed Jul 03 13:26:36 2013 -0400 summary: Relax PEP 8's perceived (but incorrect) prohibition against backslashed. files: pep-0008.txt | 18 +++++++++++++++--- 1 files changed, 15 insertions(+), 3 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -158,9 +158,21 @@ line continuation inside parentheses, brackets and braces. Long lines can be broken over multiple lines by wrapping expressions in parentheses. These should be used in preference to using a backslash -for line continuation. Make sure to indent the continued line -appropriately. The preferred place to break around a binary operator -is *after* the operator, not before it. Some examples:: +for line continuation. + +Backslashes may still be appropriate at times. For example, long, +multiple ``with``-statements cannot use implicit continuation, so +backslashes are acceptable:: + + with open('/path/to/some/file/you/want/to/read') as file_1, \ + open('/path/to/some/file/being/written', 'w') as file_2: + file_2.write(file_1.read()) + +Another such case is with ``assert`` statements. + +Make sure to indent the continued line appropriately. The preferred +place to break around a binary operator is *after* the operator, not +before it. Some examples:: class Rectangle(Blob): -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jul 3 22:37:09 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 3 Jul 2013 22:37:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogdGVzdF9mYXVsdGhh?= =?utf-8?q?ndler=3A_skip_test=5Fread=5Fnull=28=29_on_AIX?= Message-ID: <3blvJ55SNNz7Lmg@mail.python.org> http://hg.python.org/cpython/rev/217535af4567 changeset: 84434:217535af4567 branch: 3.3 parent: 84432:910ec3471d55 user: Victor Stinner date: Wed Jul 03 22:29:42 2013 +0200 summary: test_faulthandler: skip test_read_null() on AIX AIX maps the first page of memory at address zero as valid, read-only. Reading NULL is not a fault on AIX. This is utilized by IBM compiler optimizations. One speculatively can indirect through a pointer which may be null without first testing if null and defer the test before using the value. files: Lib/test/test_faulthandler.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -107,6 +107,8 @@ self.assertRegex(output, regex) self.assertNotEqual(exitcode, 0) + @unittest.skipIf(sys.platform.startswith('aix'), + "the first page of memory is a mapped read-only on AIX") def test_read_null(self): self.check_fatal_error(""" import faulthandler -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 3 22:37:11 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 3 Jul 2013 22:37:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_test=5Ffaulthandler=3A_skip_test=5Frea?= =?utf-8?b?ZF9udWxsKCkgb24gQUlY?= Message-ID: <3blvJ708HSz7LjX@mail.python.org> http://hg.python.org/cpython/rev/eea9680599a1 changeset: 84435:eea9680599a1 parent: 84433:8e838598eed1 parent: 84434:217535af4567 user: Victor Stinner date: Wed Jul 03 22:35:39 2013 +0200 summary: (Merge 3.3) test_faulthandler: skip test_read_null() on AIX AIX maps the first page of memory at address zero as valid, read-only. Reading NULL is not a fault on AIX. This is utilized by IBM compiler optimizations. One speculatively can indirect through a pointer which may be null without first testing if null and defer the test before using the value. files: Lib/test/test_faulthandler.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -107,6 +107,8 @@ self.assertRegex(output, regex) self.assertNotEqual(exitcode, 0) + @unittest.skipIf(sys.platform.startswith('aix'), + "the first page of memory is a mapped read-only on AIX") def test_read_null(self): self.check_fatal_error(""" import faulthandler -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 3 23:08:23 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 3 Jul 2013 23:08:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogdGVzdF90aW1lLnRl?= =?utf-8?q?st=5Fmonotonic=28=29=3A_use_a_longer_sleep_to_try_to_make_the_t?= =?utf-8?q?est_more?= Message-ID: <3blw070G3pzSlk@mail.python.org> http://hg.python.org/cpython/rev/13e154067de3 changeset: 84436:13e154067de3 branch: 3.3 parent: 84434:217535af4567 user: Victor Stinner date: Wed Jul 03 23:07:37 2013 +0200 summary: test_time.test_monotonic(): use a longer sleep to try to make the test more reliable files: Lib/test/test_time.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -368,11 +368,11 @@ 'need time.monotonic') def test_monotonic(self): t1 = time.monotonic() - time.sleep(0.1) + time.sleep(0.5) t2 = time.monotonic() dt = t2 - t1 self.assertGreater(t2, t1) - self.assertAlmostEqual(dt, 0.1, delta=0.2) + self.assertAlmostEqual(dt, 0.5, delta=0.2) info = time.get_clock_info('monotonic') self.assertTrue(info.monotonic) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 3 23:08:24 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 3 Jul 2013 23:08:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogKE1lcmdlIDMuMykgdGVzdF90aW1lLnRlc3RfbW9ub3RvbmljKCk6IHVz?= =?utf-8?q?e_a_longer_sleep_to_try_to_make_the?= Message-ID: <3blw082677z7Llw@mail.python.org> http://hg.python.org/cpython/rev/c9545c2386c4 changeset: 84437:c9545c2386c4 parent: 84435:eea9680599a1 parent: 84436:13e154067de3 user: Victor Stinner date: Wed Jul 03 23:07:59 2013 +0200 summary: (Merge 3.3) test_time.test_monotonic(): use a longer sleep to try to make the test more reliable files: Lib/test/test_time.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -368,11 +368,11 @@ 'need time.monotonic') def test_monotonic(self): t1 = time.monotonic() - time.sleep(0.1) + time.sleep(0.5) t2 = time.monotonic() dt = t2 - t1 self.assertGreater(t2, t1) - self.assertAlmostEqual(dt, 0.1, delta=0.2) + self.assertAlmostEqual(dt, 0.5, delta=0.2) info = time.get_clock_info('monotonic') self.assertTrue(info.monotonic) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 4 01:52:29 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 4 Jul 2013 01:52:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_PEP_446=3A_based_on_PEP_4?= =?utf-8?q?33=2C_but_simpler_and_more_conservative?= Message-ID: <3blzdT2mPHz7Ln5@mail.python.org> http://hg.python.org/peps/rev/7c1f78c181bb changeset: 4974:7c1f78c181bb user: Victor Stinner date: Thu Jul 04 01:32:07 2013 +0200 summary: Add PEP 446: based on PEP 433, but simpler and more conservative files: pep-0446.txt | 172 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 172 insertions(+), 0 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt new file mode 100644 --- /dev/null +++ b/pep-0446.txt @@ -0,0 +1,172 @@ +PEP: 446 +Title: Add new cloexec and blocking parameters to functions creating file descriptors +Version: $Revision$ +Last-Modified: $Date$ +Author: Victor Stinner +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 3-July-2013 +Python-Version: 3.4 + + +Abstract +======== + +This PEP proposes new portable parameters and functions to configure the +inherance of file descriptors and the non-blocking flag of sockets. + + +Rationale +========= + +Inherance of file descriptors +----------------------------- + +The inherance of a file descriptor in a child process at the execution +of a new program can be configured on each file descriptor using a +*close-on-exec* flag. By default, the close-on-exec flag is not set. On +Windows, file descriptors are not inherited if the ``bInheritHandles`` +parameter of the ``CreateProcess()`` function is ``FALSE``, even if the +close-on-exec flag is not set. On UNIX, file descriptors are inherited +by default. + +Inherance of file descriptors causes issues. For example, closing a file +descriptor in the parent process does not release the resource (file, +socket, ...), because the file descriptor is still open in the child +process. + +Leaking file descriptors is a major security vulnerability. An +untrusted child process can read sensitive data like passwords and +take control of the parent process though leaked file descriptors. It +is for example a known vulnerability to escape from a chroot. + + +Non-blocking sockets +-------------------- + +To handle multiple network clients in a single thread, a multiplexing +function like ``select()`` can be used. For best performances, sockets +must be configured as non-blocking. + +By default, newly created sockets are blocking. Setting the non-blocking +mode requires extra system calls. + + +Setting flags at the creation of the file descriptor +---------------------------------------------------- + +Windows and recent versions of other operating systems like Linux +support setting close-on-exec and blocking flags directly at the +creation of file descriptors and sockets. + +Setting these flags at the creation is atomic and avoids extra system +calls. + + +Proposal +======== + +New cloexec And blocking Parameters +----------------------------------- + +Add a new optional *cloexec* on functions creating file descriptors: + +* ``io.FileIO`` +* ``io.open()`` +* ``open()`` +* ``os.dup()`` +* ``os.dup2()`` +* ``os.fdopen()`` +* ``os.open()`` +* ``os.openpty()`` +* ``os.pipe()`` +* ``select.devpoll()`` +* ``select.epoll()`` +* ``select.kqueue()`` + +Add new optional *cloexec* and *blocking* parameters to functions +creating sockets: + +* ``asyncore.dispatcher.create_socket()`` +* ``socket.socket()`` +* ``socket.socket.accept()`` +* ``socket.socket.dup()`` +* ``socket.socket.fromfd`` +* ``socket.socketpair()`` + +The default value of *cloexec* is ``False``, and the default value of +*blocking* is ``True``. + +The atomicity is not guaranteed. If the platform does not support +setting close-on-exec and blocking flags at the creation of the file +descriptor, the flags are set using extra system calls. + +New Functions +------------- + +Add new functions the get and set the close-on-exec flag of a file +descriptor: + +* ``os.get_cloexec(fd:int) -> bool`` +* ``os.set_cloexec(fd:int, cloexec: bool)`` + + +Other Changes +------------- + +The ``subprocess.Popen`` class must clear the close-on-exec flag of file +descriptors of the ``pass_fds`` parameter. + +The close-on-exec flag must also be set on private file descriptors and +sockets in the Python standard library. For example, on UNIX, +os.urandom() opens ``/dev/urandom`` to read some random bytes, the file +descriptor is closed at function exit. The file descriptor is not +expected to be inherited on execution of a new program in a child +process. + + +Alternatives +============ + +The PEP 433 is a previous attempt proposing various other alternatives, +but no consensus could be reached. + +This PEP is much simpler, more conservative (no backward compatibility +issue) and has a well defined behaviour (the default value of the new +*cloexec* parameter is not configurable). + + +Links +===== + +Python issues: + +* `#10115: Support accept4() for atomic setting of flags at socket + creation `_ +* `#12105: open() does not able to set flags, such as O_CLOEXEC + `_ +* `#12107: TCP listening sockets created without FD_CLOEXEC flag + `_ +* `#16850: Add "e" mode to open(): close-and-exec + (O_CLOEXEC) / O_NOINHERIT `_ +* `#16860: Use O_CLOEXEC in the tempfile module + `_ +* `#16946: subprocess: _close_open_fd_range_safe() does not set + close-on-exec flag on Linux < 2.6.23 if O_CLOEXEC is defined + `_ +* `#17070: PEP 433: Use the new cloexec to improve security and avoid + bugs `_ + +Other links: + +* `Secure File Descriptor Handling + `_ (Ulrich Drepper, + 2008) + + +Copyright +========= + +This document has been placed into the public domain. + -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Thu Jul 4 05:43:36 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 04 Jul 2013 05:43:36 +0200 Subject: [Python-checkins] Daily reference leaks (c9545c2386c4): sum=2 Message-ID: results for c9545c2386c4 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/reflog4RbBJl', '-x'] From python-checkins at python.org Thu Jul 4 12:58:38 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 4 Jul 2013 12:58:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_446=3A_add_an_=22Overlapp?= =?utf-8?q?ed_I/O=22_alternative?= Message-ID: <3bmGQ63tKqz7LjM@mail.python.org> http://hg.python.org/peps/rev/20d12c860d89 changeset: 4975:20d12c860d89 user: Victor Stinner date: Thu Jul 04 12:58:03 2013 +0200 summary: PEP 446: add an "Overlapped I/O" alternative files: pep-0446.txt | 108 +++++++++++++++++++++++++++----------- 1 files changed, 76 insertions(+), 32 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -23,23 +23,31 @@ Inherance of file descriptors ----------------------------- -The inherance of a file descriptor in a child process at the execution -of a new program can be configured on each file descriptor using a -*close-on-exec* flag. By default, the close-on-exec flag is not set. On -Windows, file descriptors are not inherited if the ``bInheritHandles`` -parameter of the ``CreateProcess()`` function is ``FALSE``, even if the -close-on-exec flag is not set. On UNIX, file descriptors are inherited -by default. +The inherance of file descriptors in child processes can be configured +on each file descriptor using a *close-on-exec* flag. By default, the +close-on-exec flag is not set. + +On Windows, file descriptors are not inherited if the +``bInheritHandles`` parameter of the ``CreateProcess()`` function is +``FALSE``, even if the close-on-exec flag is not set. + +On UNIX, file descriptors with the close-and-exec flag set are closed at +the execution of a new program (ex: when calling ``execv()``). The flag +has no effect on ``fork()``, all file descriptors are inherited by the +child process. + +Issues of the inherance of file descriptors +------------------------------------------- Inherance of file descriptors causes issues. For example, closing a file descriptor in the parent process does not release the resource (file, socket, ...), because the file descriptor is still open in the child process. -Leaking file descriptors is a major security vulnerability. An -untrusted child process can read sensitive data like passwords and -take control of the parent process though leaked file descriptors. It -is for example a known vulnerability to escape from a chroot. +Leaking file descriptors is also a major security vulnerability. An +untrusted child process can read sensitive data like passwords and take +control of the parent process though leaked file descriptors. It is for +example a known vulnerability to escape from a chroot. Non-blocking sockets @@ -47,21 +55,24 @@ To handle multiple network clients in a single thread, a multiplexing function like ``select()`` can be used. For best performances, sockets -must be configured as non-blocking. +must be configured as non-blocking. Operations like ``send()`` and +``recv()`` return an ``EAGAIN`` or ``EWOULDBLOCK`` error if the +operation would block. By default, newly created sockets are blocking. Setting the non-blocking -mode requires extra system calls. +mode requires additional system calls. Setting flags at the creation of the file descriptor ---------------------------------------------------- Windows and recent versions of other operating systems like Linux -support setting close-on-exec and blocking flags directly at the -creation of file descriptors and sockets. +support setting the close-on-exec flag directly at the creation of file +descriptors, and close-on-exec and blocking flags at the creation of +sockets. -Setting these flags at the creation is atomic and avoids extra system -calls. +Setting these flags at the creation is atomic and avoids additional +system calls. Proposal @@ -95,12 +106,12 @@ * ``socket.socket.fromfd`` * ``socket.socketpair()`` -The default value of *cloexec* is ``False``, and the default value of +The default value of *cloexec* is ``False`` and the default value of *blocking* is ``True``. The atomicity is not guaranteed. If the platform does not support setting close-on-exec and blocking flags at the creation of the file -descriptor, the flags are set using extra system calls. +descriptor or socket, the flags are set using additional system calls. New Functions ------------- @@ -120,21 +131,54 @@ The close-on-exec flag must also be set on private file descriptors and sockets in the Python standard library. For example, on UNIX, -os.urandom() opens ``/dev/urandom`` to read some random bytes, the file -descriptor is closed at function exit. The file descriptor is not -expected to be inherited on execution of a new program in a child -process. +os.urandom() opens ``/dev/urandom`` to read some random bytes and the +file descriptor is closed at function exit. The file descriptor is not +expected to be inherited by child processes. -Alternatives -============ +Rejected Alternatives +===================== -The PEP 433 is a previous attempt proposing various other alternatives, -but no consensus could be reached. +PEP 433 +------- -This PEP is much simpler, more conservative (no backward compatibility -issue) and has a well defined behaviour (the default value of the new -*cloexec* parameter is not configurable). +The PEP 433 entitled "Easier suppression of file descriptor inheritance" +is a previous attempt proposing various other alternatives, but no +consensus could be reached. + +This PEP has a well defined behaviour (the default value of the new +*cloexec* parameter is not configurable), is more conservative (no +backward compatibility issue), and is much simpler. + + +Add blocking parameter for file descriptors and Windows overlapped I/O +---------------------------------------------------------------------- + +Windows supports non-blocking operations on files using an extension of +the Windows API called "Overlapped I/O". Using this extension requires +to modify the Python standard library and applications to pass a +``OVERLAPPED`` structure and an event loop to wait for the completion of +operations. + +This PEP only tries to expose portable flags on file descriptors and +sockets. Supporting overlapped I/O requires an abstraction providing a +high-level and portable API for asynchronous operations on files and +sockets. Overlapped I/O are out of the scope of this PEP. + +UNIX supports non-blocking files, moreover recent versions of operating +systems support setting the non-blocking flag at the creation of a file +descriptor. It would be possible to add a new optional *blocking* +parameter to Python functions creating file descriptors. On Windows, +creating a file descriptor with ``blocking=False`` would raise a +``NotImplementedError``. This behaviour is not acceptable for the ``os`` +module which is designed as a thin wrapper on the C functions of the +operating system. If a platform does not support a function, the +function should not be available on the platform. For example, +the ``os.fork()`` function is not available on Windows. + +For all these reasons, this alternative was rejected. The PEP 3156 +proposes an abstraction for asynchronous I/O supporting non-blocking +files on Windows. Links @@ -155,8 +199,8 @@ * `#16946: subprocess: _close_open_fd_range_safe() does not set close-on-exec flag on Linux < 2.6.23 if O_CLOEXEC is defined `_ -* `#17070: PEP 433: Use the new cloexec to improve security and avoid - bugs `_ +* `#17070: Use the new cloexec to improve security and avoid bugs + `_ Other links: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jul 4 13:01:44 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 4 Jul 2013 13:01:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_446=3A_better_title?= Message-ID: <3bmGTh6fRDz7LjM@mail.python.org> http://hg.python.org/peps/rev/105a96abaebe changeset: 4976:105a96abaebe user: Victor Stinner date: Thu Jul 04 13:01:38 2013 +0200 summary: PEP 446: better title files: pep-0446.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -1,5 +1,5 @@ PEP: 446 -Title: Add new cloexec and blocking parameters to functions creating file descriptors +Title: Add new parameters to configure the inherance of files and for non-blocking sockets Version: $Revision$ Last-Modified: $Date$ Author: Victor Stinner -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jul 4 21:05:43 2013 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 4 Jul 2013 21:05:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzExMTg1?= =?utf-8?q?=3A_Fix_test=5Fwait4_under_AIX=2E__Patch_by_S=C3=A9bastien_Sabl?= =?utf-8?b?w6ku?= Message-ID: <3bmTD74NZrz7Lkm@mail.python.org> http://hg.python.org/cpython/rev/b3ea1b5a1617 changeset: 84438:b3ea1b5a1617 branch: 3.3 parent: 84436:13e154067de3 user: Antoine Pitrou date: Thu Jul 04 21:03:10 2013 +0200 summary: Issue #11185: Fix test_wait4 under AIX. Patch by S?bastien Sabl?. files: Lib/test/test_wait4.py | 8 +++++++- Misc/NEWS | 2 ++ 2 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_wait4.py b/Lib/test/test_wait4.py --- a/Lib/test/test_wait4.py +++ b/Lib/test/test_wait4.py @@ -3,6 +3,7 @@ import os import time +import sys from test.fork_wait import ForkWait from test.support import run_unittest, reap_children, get_attribute @@ -13,10 +14,15 @@ class Wait4Test(ForkWait): def wait_impl(self, cpid): + option = os.WNOHANG + if sys.platform.startswith('aix'): + # Issue #11185: wait4 is broken on AIX and will always return 0 + # with WNOHANG. + option = 0 for i in range(10): # wait4() shouldn't hang, but some of the buildbots seem to hang # in the forking tests. This is an attempt to fix the problem. - spid, status, rusage = os.wait4(cpid, os.WNOHANG) + spid, status, rusage = os.wait4(cpid, option) if spid == cpid: break time.sleep(1.0) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -155,6 +155,8 @@ Tests ----- +- Issue #11185: Fix test_wait4 under AIX. Patch by S?bastien Sabl?. + - Issue #17691: test_univnewlines now works with unittest test discovery. Patch by Zachary Ware. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 4 21:05:44 2013 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 4 Jul 2013 21:05:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2311185=3A_Fix_test=5Fwait4_under_AIX=2E__Patch_b?= =?utf-8?b?eSBTw6liYXN0aWVuIFNhYmzDqS4=?= Message-ID: <3bmTD86bsJz7Lpx@mail.python.org> http://hg.python.org/cpython/rev/8055521e372f changeset: 84439:8055521e372f parent: 84437:c9545c2386c4 parent: 84438:b3ea1b5a1617 user: Antoine Pitrou date: Thu Jul 04 21:05:30 2013 +0200 summary: Issue #11185: Fix test_wait4 under AIX. Patch by S?bastien Sabl?. files: Lib/test/test_wait4.py | 8 +++++++- Misc/NEWS | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_wait4.py b/Lib/test/test_wait4.py --- a/Lib/test/test_wait4.py +++ b/Lib/test/test_wait4.py @@ -3,6 +3,7 @@ import os import time +import sys from test.fork_wait import ForkWait from test.support import run_unittest, reap_children, get_attribute @@ -13,10 +14,15 @@ class Wait4Test(ForkWait): def wait_impl(self, cpid): + option = os.WNOHANG + if sys.platform.startswith('aix'): + # Issue #11185: wait4 is broken on AIX and will always return 0 + # with WNOHANG. + option = 0 for i in range(10): # wait4() shouldn't hang, but some of the buildbots seem to hang # in the forking tests. This is an attempt to fix the problem. - spid, status, rusage = os.wait4(cpid, os.WNOHANG) + spid, status, rusage = os.wait4(cpid, option) if spid == cpid: break time.sleep(1.0) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -465,10 +465,11 @@ - Implement PEP 435 "Adding an Enum type to the Python standard library". - Tests ----- +- Issue #11185: Fix test_wait4 under AIX. Patch by S?bastien Sabl?. + - Issue #18207: Fix test_ssl for some versions of OpenSSL that ignore seconds in ASN1_TIME fields. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 4 21:06:19 2013 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 4 Jul 2013 21:06:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Consolidate_tests_section?= =?utf-8?q?=2E?= Message-ID: <3bmTDq2yZpz7Lmd@mail.python.org> http://hg.python.org/cpython/rev/efdb4320219b changeset: 84440:efdb4320219b user: Antoine Pitrou date: Thu Jul 04 21:06:12 2013 +0200 summary: Consolidate tests section. files: Misc/NEWS | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -519,6 +519,8 @@ - Issue #17692: test_sqlite now works with unittest test discovery. Patch by Zachary Ware. +- Issue #11995: test_pydoc doesn't import all sys.path modules anymore. + Documentation ------------- @@ -534,11 +536,6 @@ - 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 ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 4 21:11:20 2013 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 4 Jul 2013 21:11:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzExMTg1?= =?utf-8?q?=3A_Fix_test=5Fwait4_under_AIX=2E__Patch_by_S=C3=A9bastien_Sabl?= =?utf-8?b?w6ku?= Message-ID: <3bmTLc542jz7Lpk@mail.python.org> http://hg.python.org/cpython/rev/e3fd5fc5dc47 changeset: 84441:e3fd5fc5dc47 branch: 2.7 parent: 84431:5896f887a93a user: Antoine Pitrou date: Thu Jul 04 21:03:10 2013 +0200 summary: Issue #11185: Fix test_wait4 under AIX. Patch by S?bastien Sabl?. files: Lib/test/test_wait4.py | 8 +++++++- Misc/NEWS | 2 ++ 2 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_wait4.py b/Lib/test/test_wait4.py --- a/Lib/test/test_wait4.py +++ b/Lib/test/test_wait4.py @@ -3,6 +3,7 @@ import os import time +import sys from test.fork_wait import ForkWait from test.test_support import run_unittest, reap_children, get_attribute @@ -13,10 +14,15 @@ class Wait4Test(ForkWait): def wait_impl(self, cpid): + option = os.WNOHANG + if sys.platform.startswith('aix'): + # Issue #11185: wait4 is broken on AIX and will always return 0 + # with WNOHANG. + option = 0 for i in range(10): # wait4() shouldn't hang, but some of the buildbots seem to hang # in the forking tests. This is an attempt to fix the problem. - spid, status, rusage = os.wait4(cpid, os.WNOHANG) + spid, status, rusage = os.wait4(cpid, option) if spid == cpid: break time.sleep(1.0) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,8 @@ Tests ----- +- Issue #11185: Fix test_wait4 under AIX. Patch by S?bastien Sabl?. + - Issue #18094: test_uuid no more reports skipped tests as passed. - Issue #11995: test_pydoc doesn't import all sys.path modules anymore. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 4 22:10:56 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 4 Jul 2013 22:10:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_446=3A_typo=3A_inherance_?= =?utf-8?q?=3D=3E_inheritance?= Message-ID: <3bmVgN4M6kz7LqQ@mail.python.org> http://hg.python.org/peps/rev/39553edc98e2 changeset: 4977:39553edc98e2 user: Victor Stinner date: Thu Jul 04 22:10:39 2013 +0200 summary: PEP 446: typo: inherance => inheritance files: pep-0446.txt | 22 +++++++++++----------- 1 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -1,5 +1,5 @@ PEP: 446 -Title: Add new parameters to configure the inherance of files and for non-blocking sockets +Title: Add new parameters to configure the inheritance of files and for non-blocking sockets Version: $Revision$ Last-Modified: $Date$ Author: Victor Stinner @@ -14,16 +14,16 @@ ======== This PEP proposes new portable parameters and functions to configure the -inherance of file descriptors and the non-blocking flag of sockets. +inheritance of file descriptors and the non-blocking flag of sockets. Rationale ========= -Inherance of file descriptors ------------------------------ +Inheritance of file descriptors +------------------------------- -The inherance of file descriptors in child processes can be configured +The inheritance of file descriptors in child processes can be configured on each file descriptor using a *close-on-exec* flag. By default, the close-on-exec flag is not set. @@ -36,13 +36,13 @@ has no effect on ``fork()``, all file descriptors are inherited by the child process. -Issues of the inherance of file descriptors -------------------------------------------- +Issues of the inheritance of file descriptors +--------------------------------------------- -Inherance of file descriptors causes issues. For example, closing a file -descriptor in the parent process does not release the resource (file, -socket, ...), because the file descriptor is still open in the child -process. +Inheritance of file descriptors causes issues. For example, closing a +file descriptor in the parent process does not release the resource +(file, socket, ...), because the file descriptor is still open in the +child process. Leaking file descriptors is also a major security vulnerability. An untrusted child process can read sensitive data like passwords and take -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Jul 5 00:16:32 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 5 Jul 2013 00:16:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318200=3A_Back_out?= =?utf-8?q?_usage_of_ModuleNotFoundError_=288d28d44f3a9a=29?= Message-ID: <3bmYSJ293zz7LlN@mail.python.org> http://hg.python.org/cpython/rev/7769c4d72806 changeset: 84442:7769c4d72806 parent: 84440:efdb4320219b user: Brett Cannon date: Thu Jul 04 17:43:24 2013 -0400 summary: Issue #18200: Back out usage of ModuleNotFoundError (8d28d44f3a9a) files: Lib/_dummy_thread.py | 2 +- Lib/_osx_support.py | 2 +- Lib/_pyio.py | 4 ++-- Lib/_strptime.py | 2 +- Lib/bisect.py | 2 +- Lib/bz2.py | 2 +- Lib/cmd.py | 4 ++-- Lib/code.py | 2 +- Lib/collections/__init__.py | 2 +- Lib/copy.py | 2 +- Lib/datetime.py | 2 +- Lib/decimal.py | 8 ++++---- Lib/distutils/archive_util.py | 2 +- Lib/distutils/ccompiler.py | 7 ++++--- Lib/distutils/dist.py | 9 +++++---- Lib/distutils/msvccompiler.py | 4 ++-- Lib/distutils/util.py | 2 +- Lib/encodings/__init__.py | 7 ++++--- Lib/ftplib.py | 2 +- Lib/functools.py | 6 +++--- Lib/getopt.py | 2 +- Lib/getpass.py | 2 +- Lib/hashlib.py | 4 ++-- Lib/heapq.py | 2 +- Lib/http/client.py | 2 +- Lib/http/cookiejar.py | 2 +- Lib/http/server.py | 2 +- Lib/imaplib.py | 2 +- Lib/imp.py | 2 +- Lib/importlib/__init__.py | 2 +- Lib/importlib/abc.py | 2 +- Lib/inspect.py | 2 +- Lib/json/decoder.py | 2 +- Lib/json/encoder.py | 4 ++-- Lib/json/scanner.py | 2 +- Lib/lib2to3/refactor.py | 2 +- Lib/locale.py | 2 +- Lib/logging/__init__.py | 2 +- Lib/logging/config.py | 2 +- Lib/logging/handlers.py | 4 ++-- Lib/macpath.py | 2 +- Lib/mailbox.py | 2 +- Lib/mimetypes.py | 2 +- Lib/multiprocessing/connection.py | 2 +- Lib/multiprocessing/forking.py | 2 +- Lib/nntplib.py | 2 +- Lib/ntpath.py | 4 ++-- Lib/operator.py | 2 +- Lib/optparse.py | 2 +- Lib/os.py | 14 +++++++------- Lib/pdb.py | 2 +- Lib/pickle.py | 4 ++-- Lib/platform.py | 14 +++++++------- Lib/poplib.py | 2 +- Lib/pstats.py | 2 +- Lib/pty.py | 2 +- Lib/pydoc.py | 4 ++-- Lib/queue.py | 4 ++-- Lib/quopri.py | 2 +- Lib/reprlib.py | 2 +- Lib/rlcompleter.py | 2 +- Lib/sched.py | 4 ++-- Lib/shutil.py | 10 +++++----- Lib/site.py | 6 +++--- Lib/smtpd.py | 2 +- Lib/smtplib.py | 2 +- Lib/socket.py | 2 +- Lib/socketserver.py | 2 +- Lib/sqlite3/test/dbapi.py | 2 +- Lib/sqlite3/test/types.py | 2 +- Lib/sre_compile.py | 2 +- Lib/ssl.py | 4 ++-- Lib/subprocess.py | 2 +- Lib/tarfile.py | 12 ++++++------ Lib/tempfile.py | 4 ++-- Lib/threading.py | 6 +++--- Lib/trace.py | 4 ++-- Lib/urllib/request.py | 6 +++--- Lib/venv/__init__.py | 2 +- Lib/warnings.py | 6 +++--- Lib/xml/etree/ElementTree.py | 10 +++++----- Lib/xml/sax/expatreader.py | 17 ++++++++++++++--- Lib/xmlrpc/client.py | 2 +- 83 files changed, 158 insertions(+), 144 deletions(-) diff --git a/Lib/_dummy_thread.py b/Lib/_dummy_thread.py --- a/Lib/_dummy_thread.py +++ b/Lib/_dummy_thread.py @@ -7,7 +7,7 @@ try: import _thread - except ModuleNotFoundError: + except ImportError: import _dummy_thread as _thread """ diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py --- a/Lib/_osx_support.py +++ b/Lib/_osx_support.py @@ -62,7 +62,7 @@ try: import tempfile fp = tempfile.NamedTemporaryFile() - except ModuleNotFoundError: + except ImportError: fp = open("/tmp/_osx_support.%s"%( os.getpid(),), "w+b") diff --git a/Lib/_pyio.py b/Lib/_pyio.py --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -9,7 +9,7 @@ # Import _thread instead of threading to reduce startup cost try: from _thread import allocate_lock as Lock -except ModuleNotFoundError: +except ImportError: from _dummy_thread import allocate_lock as Lock import io @@ -1486,7 +1486,7 @@ if encoding is None: try: import locale - except ModuleNotFoundError: + except ImportError: # Importing locale may fail if Python is being built encoding = "ascii" else: diff --git a/Lib/_strptime.py b/Lib/_strptime.py --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -21,7 +21,7 @@ timezone as datetime_timezone) try: from _thread import allocate_lock as _thread_allocate_lock -except ModuleNotFoundError: +except ImportError: from _dummy_thread import allocate_lock as _thread_allocate_lock __all__ = [] diff --git a/Lib/bisect.py b/Lib/bisect.py --- a/Lib/bisect.py +++ b/Lib/bisect.py @@ -88,5 +88,5 @@ # Overwrite above definitions with a fast C implementation try: from _bisect import * -except ModuleNotFoundError: +except ImportError: pass diff --git a/Lib/bz2.py b/Lib/bz2.py --- a/Lib/bz2.py +++ b/Lib/bz2.py @@ -14,7 +14,7 @@ try: from threading import RLock -except ModuleNotFoundError: +except ImportError: from dummy_threading import RLock from _bz2 import BZ2Compressor, BZ2Decompressor diff --git a/Lib/cmd.py b/Lib/cmd.py --- a/Lib/cmd.py +++ b/Lib/cmd.py @@ -109,7 +109,7 @@ self.old_completer = readline.get_completer() readline.set_completer(self.complete) readline.parse_and_bind(self.completekey+": complete") - except ModuleNotFoundError: + except ImportError: pass try: if intro is not None: @@ -143,7 +143,7 @@ try: import readline readline.set_completer(self.old_completer) - except ModuleNotFoundError: + except ImportError: pass diff --git a/Lib/code.py b/Lib/code.py --- a/Lib/code.py +++ b/Lib/code.py @@ -293,7 +293,7 @@ else: try: import readline - except ModuleNotFoundError: + except ImportError: pass console.interact(banner) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -395,7 +395,7 @@ try: # Load C helper function if available from _collections import _count_elements -except ModuleNotFoundError: +except ImportError: pass class Counter(dict): diff --git a/Lib/copy.py b/Lib/copy.py --- a/Lib/copy.py +++ b/Lib/copy.py @@ -59,7 +59,7 @@ try: from org.python.core import PyStringMap -except ModuleNotFoundError: +except ImportError: PyStringMap = None __all__ = ["Error", "copy", "deepcopy"] diff --git a/Lib/datetime.py b/Lib/datetime.py --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -2116,7 +2116,7 @@ try: from _datetime import * -except ModuleNotFoundError: +except ImportError: pass else: # Clean up unused names diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -149,7 +149,7 @@ try: from collections import namedtuple as _namedtuple DecimalTuple = _namedtuple('DecimalTuple', 'sign digits exponent') -except ModuleNotFoundError: +except ImportError: DecimalTuple = lambda *args: args # Rounding @@ -430,7 +430,7 @@ try: import threading -except ModuleNotFoundError: +except ImportError: # Python was compiled without threads; create a mock object instead class MockThreading(object): def local(self, sys=sys): @@ -6147,7 +6147,7 @@ # don't care too much if locale isn't present. try: import locale as _locale -except ModuleNotFoundError: +except ImportError: pass def _parse_format_specifier(format_spec, _localeconv=None): @@ -6391,7 +6391,7 @@ try: import _decimal -except ModuleNotFoundError: +except ImportError: pass else: s1 = set(dir()) diff --git a/Lib/distutils/archive_util.py b/Lib/distutils/archive_util.py --- a/Lib/distutils/archive_util.py +++ b/Lib/distutils/archive_util.py @@ -9,7 +9,7 @@ try: import zipfile -except ModuleNotFoundError: +except ImportError: zipfile = None diff --git a/Lib/distutils/ccompiler.py b/Lib/distutils/ccompiler.py --- a/Lib/distutils/ccompiler.py +++ b/Lib/distutils/ccompiler.py @@ -3,7 +3,7 @@ Contains CCompiler, an abstract base class that defines the interface for the Distutils compiler abstraction model.""" -import importlib, sys, os, re +import sys, os, re from distutils.errors import * from distutils.spawn import spawn from distutils.file_util import move_file @@ -1013,9 +1013,10 @@ try: module_name = "distutils." + module_name - module = importlib.import_module(module_name) + __import__ (module_name) + module = sys.modules[module_name] klass = vars(module)[class_name] - except ModuleNotFoundError: + except ImportError: raise DistutilsModuleError( "can't compile C/C++ code: unable to load module '%s'" % \ module_name) diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py --- a/Lib/distutils/dist.py +++ b/Lib/distutils/dist.py @@ -4,11 +4,11 @@ being built/installed/distributed. """ -import importlib, sys, os, re +import sys, os, re try: import warnings -except ModuleNotFoundError: +except ImportError: warnings = None from distutils.errors import * @@ -788,8 +788,9 @@ klass_name = command try: - module = importlib.import_module(module_name) - except ModuleNotFoundError: + __import__ (module_name) + module = sys.modules[module_name] + except ImportError: continue try: diff --git a/Lib/distutils/msvccompiler.py b/Lib/distutils/msvccompiler.py --- a/Lib/distutils/msvccompiler.py +++ b/Lib/distutils/msvccompiler.py @@ -28,7 +28,7 @@ RegEnumValue = winreg.EnumValue RegError = winreg.error -except ModuleNotFoundError: +except ImportError: try: import win32api import win32con @@ -39,7 +39,7 @@ RegEnumKey = win32api.RegEnumKey RegEnumValue = win32api.RegEnumValue RegError = win32api.error - except ModuleNotFoundError: + except ImportError: log.info("Warning: Can't read registry to find the " "necessary compiler setting\n" "Make sure that Python modules winreg, " diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -388,7 +388,7 @@ try: from tempfile import mkstemp (script_fd, script_name) = mkstemp(".py") - except ModuleNotFoundError: + except ImportError: from tempfile import mktemp (script_fd, script_name) = None, mktemp(".py") log.info("writing byte-compilation script '%s'", script_name) diff --git a/Lib/encodings/__init__.py b/Lib/encodings/__init__.py --- a/Lib/encodings/__init__.py +++ b/Lib/encodings/__init__.py @@ -29,11 +29,11 @@ """#" import codecs -import importlib from . import aliases _cache = {} _unknown = '--unknown--' +_import_tail = ['*'] _aliases = aliases.aliases class CodecRegistryError(LookupError, SystemError): @@ -94,8 +94,9 @@ try: # Import is absolute to prevent the possibly malicious import of a # module with side-effects that is not in the 'encodings' package. - mod = importlib.import_module('encodings.' + modname) - except ModuleNotFoundError: + mod = __import__('encodings.' + modname, fromlist=_import_tail, + level=0) + except ImportError: pass else: break diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -667,7 +667,7 @@ try: import ssl -except ModuleNotFoundError: +except ImportError: _SSLSocket = None else: _SSLSocket = ssl.SSLSocket diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -15,7 +15,7 @@ try: from _functools import reduce -except ModuleNotFoundError: +except ImportError: pass from abc import get_cache_token from collections import namedtuple @@ -143,7 +143,7 @@ try: from _functools import cmp_to_key -except ModuleNotFoundError: +except ImportError: pass @@ -166,7 +166,7 @@ try: from _functools import partial -except ModuleNotFoundError: +except ImportError: pass diff --git a/Lib/getopt.py b/Lib/getopt.py --- a/Lib/getopt.py +++ b/Lib/getopt.py @@ -36,7 +36,7 @@ import os try: from gettext import gettext as _ -except ModuleNotFoundError: +except ImportError: # Bootstrapping Python: gettext's dependencies not built yet def _(s): return s diff --git a/Lib/getpass.py b/Lib/getpass.py --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -164,7 +164,7 @@ except (ImportError, AttributeError): try: import msvcrt - except ModuleNotFoundError: + except ImportError: getpass = fallback_getpass else: getpass = win_getpass diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -98,7 +98,7 @@ return _sha3.sha3_384 elif bs == '512': return _sha3.sha3_512 - except ModuleNotFoundError: + except ImportError: pass # no extension module, this hash is unsupported. raise ValueError('unsupported hash type ' + name) @@ -143,7 +143,7 @@ __get_hash = __get_openssl_constructor algorithms_available = algorithms_available.union( _hashlib.openssl_md_meth_names) -except ModuleNotFoundError: +except ImportError: new = __py_new __get_hash = __get_builtin_constructor diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -343,7 +343,7 @@ # If available, use C implementation try: from _heapq import * -except ModuleNotFoundError: +except ImportError: pass def merge(*iterables): diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -1156,7 +1156,7 @@ try: import ssl -except ModuleNotFoundError: +except ImportError: pass else: class HTTPSConnection(HTTPConnection): diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py --- a/Lib/http/cookiejar.py +++ b/Lib/http/cookiejar.py @@ -35,7 +35,7 @@ import urllib.parse, urllib.request try: import threading as _threading -except ModuleNotFoundError: +except ImportError: import dummy_threading as _threading import http.client # only for the default HTTP port from calendar import timegm diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -904,7 +904,7 @@ return nobody try: import pwd - except ModuleNotFoundError: + except ImportError: return -1 try: nobody = pwd.getpwnam('nobody')[2] diff --git a/Lib/imaplib.py b/Lib/imaplib.py --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -29,7 +29,7 @@ try: import ssl HAVE_SSL = True -except ModuleNotFoundError: +except ImportError: HAVE_SSL = False __all__ = ["IMAP4", "IMAP4_stream", "Internaldate2tuple", diff --git a/Lib/imp.py b/Lib/imp.py --- a/Lib/imp.py +++ b/Lib/imp.py @@ -12,7 +12,7 @@ _fix_co_filename) try: from _imp import load_dynamic -except ModuleNotFoundError: +except ImportError: # Platform doesn't support dynamic loading. load_dynamic = None diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -15,7 +15,7 @@ try: import _frozen_importlib as _bootstrap -except ModuleNotFoundError: +except ImportError: from . import _bootstrap _bootstrap._setup(sys, _imp) else: diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -3,7 +3,7 @@ from . import machinery try: import _frozen_importlib -except ModuleNotFoundError as exc: +except ImportError as exc: if exc.name != '_frozen_importlib': raise _frozen_importlib = None diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -50,7 +50,7 @@ # back to hardcording so the dependency is optional try: from dis import COMPILER_FLAG_NAMES as _flag_names -except ModuleNotFoundError: +except ImportError: CO_OPTIMIZED, CO_NEWLOCALS = 0x1, 0x2 CO_VARARGS, CO_VARKEYWORDS = 0x4, 0x8 CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40 diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -5,7 +5,7 @@ from json import scanner try: from _json import scanstring as c_scanstring -except ModuleNotFoundError: +except ImportError: c_scanstring = None __all__ = ['JSONDecoder'] diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -4,11 +4,11 @@ try: from _json import encode_basestring_ascii as c_encode_basestring_ascii -except ModuleNotFoundError: +except ImportError: c_encode_basestring_ascii = None try: from _json import make_encoder as c_make_encoder -except ModuleNotFoundError: +except ImportError: c_make_encoder = None ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') diff --git a/Lib/json/scanner.py b/Lib/json/scanner.py --- a/Lib/json/scanner.py +++ b/Lib/json/scanner.py @@ -3,7 +3,7 @@ import re try: from _json import make_scanner as c_make_scanner -except ModuleNotFoundError: +except ImportError: c_make_scanner = None __all__ = ['make_scanner'] diff --git a/Lib/lib2to3/refactor.py b/Lib/lib2to3/refactor.py --- a/Lib/lib2to3/refactor.py +++ b/Lib/lib2to3/refactor.py @@ -706,7 +706,7 @@ items, write, doctests_only) try: import multiprocessing - except ModuleNotFoundError: + except ImportError: raise MultiprocessingUnsupported if self.queue is not None: raise RuntimeError("already doing multiple processes") diff --git a/Lib/locale.py b/Lib/locale.py --- a/Lib/locale.py +++ b/Lib/locale.py @@ -47,7 +47,7 @@ from _locale import * -except ModuleNotFoundError: +except ImportError: # Locale emulation diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -37,7 +37,7 @@ try: import threading -except ModuleNotFoundError: #pragma: no cover +except ImportError: #pragma: no cover threading = None __author__ = "Vinay Sajip " diff --git a/Lib/logging/config.py b/Lib/logging/config.py --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -30,7 +30,7 @@ try: import _thread as thread import threading -except ModuleNotFoundError: #pragma: no cover +except ImportError: #pragma: no cover thread = None from socketserver import ThreadingTCPServer, StreamRequestHandler diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -29,7 +29,7 @@ import queue try: import threading -except ModuleNotFoundError: #pragma: no cover +except ImportError: #pragma: no cover threading = None # @@ -995,7 +995,7 @@ logging.ERROR : win32evtlog.EVENTLOG_ERROR_TYPE, logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE, } - except ModuleNotFoundError: + except ImportError: print("The Python Win32 extensions for NT (service, event "\ "logging) appear not to be available.") self._welu = None diff --git a/Lib/macpath.py b/Lib/macpath.py --- a/Lib/macpath.py +++ b/Lib/macpath.py @@ -187,7 +187,7 @@ path = abspath(path) try: import Carbon.File - except ModuleNotFoundError: + except ImportError: return path if not path: return path diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -23,7 +23,7 @@ import contextlib try: import fcntl -except ModuleNotFoundError: +except ImportError: fcntl = None __all__ = [ 'Mailbox', 'Maildir', 'mbox', 'MH', 'Babyl', 'MMDF', diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -29,7 +29,7 @@ import urllib.parse try: import winreg as _winreg -except ModuleNotFoundError: +except ImportError: _winreg = None __all__ = [ diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -27,7 +27,7 @@ try: import _winapi from _winapi import WAIT_OBJECT_0, WAIT_TIMEOUT, INFINITE -except ModuleNotFoundError: +except ImportError: if sys.platform == 'win32': raise _winapi = None diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -73,7 +73,7 @@ try: from functools import partial -except ModuleNotFoundError: +except ImportError: pass else: def _reduce_partial(p): diff --git a/Lib/nntplib.py b/Lib/nntplib.py --- a/Lib/nntplib.py +++ b/Lib/nntplib.py @@ -71,7 +71,7 @@ try: import ssl -except ModuleNotFoundError: +except ImportError: _have_ssl = False else: _have_ssl = True diff --git a/Lib/ntpath.py b/Lib/ntpath.py --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -566,7 +566,7 @@ try: from nt import _getfullpathname -except ModuleNotFoundError: # not running on Windows - mock up something sensible +except ImportError: # not running on Windows - mock up something sensible def abspath(path): """Return the absolute version of a path.""" if not isabs(path): @@ -659,6 +659,6 @@ # This is overkill on Windows - just pass the path to GetFileAttributes # and check the attribute from there. from nt import _isdir as isdir -except ModuleNotFoundError: +except ImportError: # Use genericpath.isdir as imported above. pass diff --git a/Lib/operator.py b/Lib/operator.py --- a/Lib/operator.py +++ b/Lib/operator.py @@ -360,7 +360,7 @@ try: from _operator import * -except ModuleNotFoundError: +except ImportError: pass else: from _operator import __doc__ diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -87,7 +87,7 @@ try: from gettext import gettext, ngettext -except ModuleNotFoundError: +except ImportError: def gettext(message): return message diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -52,13 +52,13 @@ try: from posix import _exit __all__.append('_exit') - except ModuleNotFoundError: + except ImportError: pass import posixpath as path try: from posix import _have_functions - except ModuleNotFoundError: + except ImportError: pass elif 'nt' in _names: @@ -68,7 +68,7 @@ try: from nt import _exit __all__.append('_exit') - except ModuleNotFoundError: + except ImportError: pass import ntpath as path @@ -78,7 +78,7 @@ try: from nt import _have_functions - except ModuleNotFoundError: + except ImportError: pass elif 'ce' in _names: @@ -88,7 +88,7 @@ try: from ce import _exit __all__.append('_exit') - except ModuleNotFoundError: + except ImportError: pass # We can use the standard Windows path. import ntpath as path @@ -99,11 +99,11 @@ try: from ce import _have_functions - except ModuleNotFoundError: + except ImportError: pass else: - raise ModuleNotFoundError('no os specific module found') + raise ImportError('no os specific module found') sys.modules['os.path'] = path from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep, diff --git a/Lib/pdb.py b/Lib/pdb.py --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -158,7 +158,7 @@ import readline # remove some common file name delimiters readline.set_completer_delims(' \t\n`@#$%^&*()=+[{]}\\|;:\'",<>?') - except ModuleNotFoundError: + except ImportError: pass self.allow_kbdint = False self.nosigint = nosigint diff --git a/Lib/pickle.py b/Lib/pickle.py --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -90,7 +90,7 @@ # Jython has PyStringMap; it's a dict subclass with string keys try: from org.python.core import PyStringMap -except ModuleNotFoundError: +except ImportError: PyStringMap = None # Pickle opcodes. See pickletools.py for extensive docs. The listing @@ -1296,7 +1296,7 @@ # Use the faster _pickle if possible try: from _pickle import * -except ModuleNotFoundError: +except ImportError: Pickler, Unpickler = _Pickler, _Unpickler # Doctest diff --git a/Lib/platform.py b/Lib/platform.py --- a/Lib/platform.py +++ b/Lib/platform.py @@ -460,7 +460,7 @@ try: # Use win32api if available from win32api import RegQueryValueEx - except ModuleNotFoundError: + except ImportError: # On Python 2.0 and later, emulate using winreg import winreg RegQueryValueEx = winreg.QueryValueEx @@ -503,7 +503,7 @@ RegCloseKey, GetVersionEx from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \ VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION - except ModuleNotFoundError: + except ImportError: # Emulate the win32api module using Python APIs try: sys.getwindowsversion @@ -661,7 +661,7 @@ # Check whether the version info module is available try: import _gestalt - except ModuleNotFoundError: + except ImportError: return None # Get the infos sysv, sysa = _mac_ver_lookup(('sysv','sysa')) @@ -697,7 +697,7 @@ try: import plistlib - except ModuleNotFoundError: + except ImportError: return None pl = plistlib.readPlist(fn) @@ -762,7 +762,7 @@ # Import the needed APIs try: import java.lang - except ModuleNotFoundError: + except ImportError: return release,vendor,vminfo,osinfo vendor = _java_getprop('java.vendor', vendor) @@ -874,7 +874,7 @@ """ try: import socket - except ModuleNotFoundError: + except ImportError: # No sockets... return default try: @@ -1138,7 +1138,7 @@ # Get processor information try: import vms_lib - except ModuleNotFoundError: + except ImportError: pass else: csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0) diff --git a/Lib/poplib.py b/Lib/poplib.py --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -20,7 +20,7 @@ try: import ssl HAVE_SSL = True -except ModuleNotFoundError: +except ImportError: HAVE_SSL = False __all__ = ["POP3","error_proto"] diff --git a/Lib/pstats.py b/Lib/pstats.py --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -528,7 +528,7 @@ import cmd try: import readline - except ModuleNotFoundError: + except ImportError: pass class ProfileBrowser(cmd.Cmd): diff --git a/Lib/pty.py b/Lib/pty.py --- a/Lib/pty.py +++ b/Lib/pty.py @@ -67,7 +67,7 @@ result = os.open(tty_name, os.O_RDWR) try: from fcntl import ioctl, I_PUSH - except ModuleNotFoundError: + except ImportError: return result try: ioctl(result, I_PUSH, "ptem") diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1892,7 +1892,7 @@ def showtopic(self, topic, more_xrefs=''): try: import pydoc_data.topics - except ModuleNotFoundError: + except ImportError: self.output.write(''' Sorry, topic and keyword documentation is not available because the module "pydoc_data.topics" could not be found. @@ -1932,7 +1932,7 @@ """ try: import pydoc_data.topics - except ModuleNotFoundError: + except ImportError: return(''' Sorry, topic and keyword documentation is not available because the module "pydoc_data.topics" could not be found. diff --git a/Lib/queue.py b/Lib/queue.py --- a/Lib/queue.py +++ b/Lib/queue.py @@ -2,13 +2,13 @@ try: import threading -except ModuleNotFoundError: +except ImportError: import dummy_threading as threading from collections import deque from heapq import heappush, heappop try: from time import monotonic as time -except ModuleNotFoundError: +except ImportError: from time import time __all__ = ['Empty', 'Full', 'Queue', 'PriorityQueue', 'LifoQueue'] diff --git a/Lib/quopri.py b/Lib/quopri.py --- a/Lib/quopri.py +++ b/Lib/quopri.py @@ -13,7 +13,7 @@ try: from binascii import a2b_qp, b2a_qp -except ModuleNotFoundError: +except ImportError: a2b_qp = None b2a_qp = None diff --git a/Lib/reprlib.py b/Lib/reprlib.py --- a/Lib/reprlib.py +++ b/Lib/reprlib.py @@ -6,7 +6,7 @@ from itertools import islice try: from _thread import get_ident -except ModuleNotFoundError: +except ImportError: from _dummy_thread import get_ident def recursive_repr(fillvalue='...'): diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -154,7 +154,7 @@ try: import readline -except ModuleNotFoundError: +except ImportError: pass else: readline.set_completer(Completer().complete) diff --git a/Lib/sched.py b/Lib/sched.py --- a/Lib/sched.py +++ b/Lib/sched.py @@ -33,11 +33,11 @@ from collections import namedtuple try: import threading -except ModuleNotFoundError: +except ImportError: import dummy_threading as threading try: from time import monotonic as _time -except ModuleNotFoundError: +except ImportError: from time import time as _time __all__ = ["scheduler"] diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -17,17 +17,17 @@ import bz2 del bz2 _BZ2_SUPPORTED = True -except ModuleNotFoundError: +except ImportError: _BZ2_SUPPORTED = False try: from pwd import getpwnam -except ModuleNotFoundError: +except ImportError: getpwnam = None try: from grp import getgrnam -except ModuleNotFoundError: +except ImportError: getgrnam = None __all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", @@ -668,7 +668,7 @@ # command. try: import zipfile - except ModuleNotFoundError: + except ImportError: zipfile = None if zipfile is None: @@ -858,7 +858,7 @@ """ try: import zipfile - except ModuleNotFoundError: + except ImportError: raise ReadError('zlib not supported, cannot unpack this archive.') if not zipfile.is_zipfile(filename): diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -469,7 +469,7 @@ try: import readline import rlcompleter - except ModuleNotFoundError: + except ImportError: return # Reading the initialization (config) file may not be enough to set a @@ -570,7 +570,7 @@ """Run custom site specific code, if available.""" try: import sitecustomize - except ModuleNotFoundError: + except ImportError: pass except Exception as err: if os.environ.get("PYTHONVERBOSE"): @@ -586,7 +586,7 @@ """Run custom user specific code, if available.""" try: import usercustomize - except ModuleNotFoundError: + except ImportError: pass except Exception as err: if os.environ.get("PYTHONVERBOSE"): diff --git a/Lib/smtpd.py b/Lib/smtpd.py --- a/Lib/smtpd.py +++ b/Lib/smtpd.py @@ -846,7 +846,7 @@ if options.setuid: try: import pwd - except ModuleNotFoundError: + except ImportError: print('Cannot import module "pwd"; try running with -n option.', file=sys.stderr) sys.exit(1) nobody = pwd.getpwnam('nobody')[2] diff --git a/Lib/smtplib.py b/Lib/smtplib.py --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -171,7 +171,7 @@ try: import ssl -except ModuleNotFoundError: +except ImportError: _have_ssl = False else: _have_ssl = True diff --git a/Lib/socket.py b/Lib/socket.py --- a/Lib/socket.py +++ b/Lib/socket.py @@ -51,7 +51,7 @@ try: import errno -except ModuleNotFoundError: +except ImportError: errno = None EBADF = getattr(errno, 'EBADF', 9) EAGAIN = getattr(errno, 'EAGAIN', 11) diff --git a/Lib/socketserver.py b/Lib/socketserver.py --- a/Lib/socketserver.py +++ b/Lib/socketserver.py @@ -136,7 +136,7 @@ import errno try: import threading -except ModuleNotFoundError: +except ImportError: import dummy_threading as threading __all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer", diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py --- a/Lib/sqlite3/test/dbapi.py +++ b/Lib/sqlite3/test/dbapi.py @@ -25,7 +25,7 @@ import sqlite3 as sqlite try: import threading -except ModuleNotFoundError: +except ImportError: threading = None from test.support import TESTFN, unlink diff --git a/Lib/sqlite3/test/types.py b/Lib/sqlite3/test/types.py --- a/Lib/sqlite3/test/types.py +++ b/Lib/sqlite3/test/types.py @@ -26,7 +26,7 @@ import sqlite3 as sqlite try: import zlib -except ModuleNotFoundError: +except ImportError: zlib = None diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -295,7 +295,7 @@ def _optimize_unicode(charset, fixup): try: import array - except ModuleNotFoundError: + except ImportError: return charset charmap = [0]*65536 negate = 0 diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -127,14 +127,14 @@ try: from _ssl import PROTOCOL_SSLv2 _SSLv2_IF_EXISTS = PROTOCOL_SSLv2 -except ModuleNotFoundError: +except ImportError: _SSLv2_IF_EXISTS = None else: _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2" try: from _ssl import PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2 -except ModuleNotFoundError: +except ImportError: pass else: _PROTOCOL_NAMES[PROTOCOL_TLSv1_1] = "TLSv1.1" diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -353,7 +353,7 @@ import errno try: from time import monotonic as _time -except ModuleNotFoundError: +except ImportError: from time import time as _time # Exception classes used by this module. diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -50,7 +50,7 @@ try: import grp, pwd -except ModuleNotFoundError: +except ImportError: grp = pwd = None # os.symlink on Windows prior to 6.0 raises NotImplementedError @@ -381,7 +381,7 @@ if comptype == "gz": try: import zlib - except ModuleNotFoundError: + except ImportError: raise CompressionError("zlib module is not available") self.zlib = zlib self.crc = zlib.crc32(b"") @@ -394,7 +394,7 @@ elif comptype == "bz2": try: import bz2 - except ModuleNotFoundError: + except ImportError: raise CompressionError("bz2 module is not available") if mode == "r": self.dbuf = b"" @@ -406,7 +406,7 @@ elif comptype == "xz": try: import lzma - except ModuleNotFoundError: + except ImportError: raise CompressionError("lzma module is not available") if mode == "r": self.dbuf = b"" @@ -1654,7 +1654,7 @@ try: import bz2 - except ModuleNotFoundError: + except ImportError: raise CompressionError("bz2 module is not available") fileobj = bz2.BZ2File(fileobj or name, mode, @@ -1678,7 +1678,7 @@ try: import lzma - except ModuleNotFoundError: + except ImportError: raise CompressionError("lzma module is not available") fileobj = lzma.LZMAFile(fileobj or name, mode, preset=preset) diff --git a/Lib/tempfile.py b/Lib/tempfile.py --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -36,7 +36,7 @@ try: import fcntl as _fcntl -except ModuleNotFoundError: +except ImportError: def _set_cloexec(fd): pass else: @@ -53,7 +53,7 @@ try: import _thread -except ModuleNotFoundError: +except ImportError: import _dummy_thread as _thread _allocate_lock = _thread.allocate_lock diff --git a/Lib/threading.py b/Lib/threading.py --- a/Lib/threading.py +++ b/Lib/threading.py @@ -6,14 +6,14 @@ from time import sleep as _sleep try: from time import monotonic as _time -except ModuleNotFoundError: +except ImportError: from time import time as _time from traceback import format_exc as _format_exc from _weakrefset import WeakSet from itertools import islice as _islice try: from _collections import deque as _deque -except ModuleNotFoundError: +except ImportError: from collections import deque as _deque # Note regarding PEP 8 compliant names @@ -922,7 +922,7 @@ try: from _thread import _local as local -except ModuleNotFoundError: +except ImportError: from _threading_local import local diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -61,12 +61,12 @@ from warnings import warn as _warn try: from time import monotonic as _time -except ModuleNotFoundError: +except ImportError: from time import time as _time try: import threading -except ModuleNotFoundError: +except ImportError: _settrace = sys.settrace def _unsettrace(): diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -110,7 +110,7 @@ # check for SSL try: import ssl -except ModuleNotFoundError: +except ImportError: _have_ssl = False else: _have_ssl = True @@ -2512,7 +2512,7 @@ proxies = {} try: import winreg - except ModuleNotFoundError: + except ImportError: # Std module, so should be around - but you never know! return proxies try: @@ -2560,7 +2560,7 @@ def proxy_bypass_registry(host): try: import winreg - except ModuleNotFoundError: + except ImportError: # Std modules, so should be around - but you never know! return 0 try: diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -35,7 +35,7 @@ import sysconfig try: import threading -except ModuleNotFoundError: +except ImportError: threading = None logger = logging.getLogger(__name__) diff --git a/Lib/warnings.py b/Lib/warnings.py --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -144,8 +144,8 @@ module = category[:i] klass = category[i+1:] try: - m = __import__(module, fromlist[klass]) - except ModuleNotFoundError: + m = __import__(module, None, None, [klass]) + except ImportError: raise _OptionError("invalid module name: %r" % (module,)) try: cat = getattr(m, klass) @@ -362,7 +362,7 @@ defaultaction = _defaultaction onceregistry = _onceregistry _warnings_defaults = True -except ModuleNotFoundError: +except ImportError: filters = [] defaultaction = "default" onceregistry = {} 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 @@ -1439,13 +1439,13 @@ def __init__(self, html=0, target=None, encoding=None): try: from xml.parsers import expat - except ModuleNotFoundError: + except ImportError: try: import pyexpat as expat - except ModuleNotFoundError: - raise ModuleNotFoundError( - "No module named expat; use SimpleXMLTreeBuilder instead", - name='expat') + except ImportError: + raise ImportError( + "No module named expat; use SimpleXMLTreeBuilder instead" + ) parser = expat.ParserCreate(encoding, "}") if target is None: target = TreeBuilder() diff --git a/Lib/xml/sax/expatreader.py b/Lib/xml/sax/expatreader.py --- a/Lib/xml/sax/expatreader.py +++ b/Lib/xml/sax/expatreader.py @@ -20,7 +20,7 @@ try: from xml.parsers import expat -except ModuleNotFoundError: +except ImportError: raise SAXReaderNotAvailable("expat not supported", None) else: if not hasattr(expat, "ParserCreate"): @@ -30,7 +30,18 @@ AttributesImpl = xmlreader.AttributesImpl AttributesNSImpl = xmlreader.AttributesNSImpl -import weakref +# If we're using a sufficiently recent version of Python, we can use +# weak references to avoid cycles between the parser and content +# handler, otherwise we'll just have to pretend. +try: + import _weakref +except ImportError: + def _mkproxy(o): + return o +else: + import weakref + _mkproxy = weakref.proxy + del weakref, _weakref # --- ExpatLocator @@ -41,7 +52,7 @@ a circular reference between the parser and the content handler. """ def __init__(self, parser): - self._ref = weakref.proxy(parser) + self._ref = _mkproxy(parser) def getColumnNumber(self): parser = self._ref diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -139,7 +139,7 @@ from io import BytesIO try: import gzip -except ModuleNotFoundError: +except ImportError: gzip = None #python can be built without zlib/gzip support # -------------------------------------------------------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 5 00:16:33 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 5 Jul 2013 00:16:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315767=3A_Back_out?= =?utf-8?q?_8d28d44f3a9a_related_to_ModuleNotFoundError=2E?= Message-ID: <3bmYSK47S3z7Lqw@mail.python.org> http://hg.python.org/cpython/rev/0e4e062751fa changeset: 84443:0e4e062751fa user: Brett Cannon date: Thu Jul 04 17:44:08 2013 -0400 summary: Issue #15767: Back out 8d28d44f3a9a related to ModuleNotFoundError. files: Lib/test/test_importlib/import_/test_api.py | 7 ------- 1 files changed, 0 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_importlib/import_/test_api.py b/Lib/test/test_importlib/import_/test_api.py --- a/Lib/test/test_importlib/import_/test_api.py +++ b/Lib/test/test_importlib/import_/test_api.py @@ -26,13 +26,6 @@ with self.assertRaises(ModuleNotFoundError): util.import_('some module that does not exist') - def test_raises_ModuleNotFoundError_for_None(self): - # None in sys.modules should raise ModuleNotFoundError. - with importlib_test_util.uncache('not_here'): - sys.modules['not_here'] = None - with self.assertRaises(ModuleNotFoundError): - util.import_('not_here') - def test_name_requires_rparition(self): # Raise TypeError if a non-string is passed in for the module name. with self.assertRaises(TypeError): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 5 00:16:35 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 5 Jul 2013 00:16:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315767=3A_Revert_3?= =?utf-8?q?a50025f1900_for_ModuleNotFoundError?= Message-ID: <3bmYSM0HhKz7Lqj@mail.python.org> http://hg.python.org/cpython/rev/e3ec8b176a80 changeset: 84444:e3ec8b176a80 user: Brett Cannon date: Thu Jul 04 17:48:16 2013 -0400 summary: Issue #15767: Revert 3a50025f1900 for ModuleNotFoundError files: Doc/c-api/exceptions.rst | 7 - Doc/library/exceptions.rst | 3 +- Doc/reference/import.rst | 12 +- Doc/whatsnew/3.4.rst | 3 +- Include/pyerrors.h | 3 - Lib/importlib/_bootstrap.py | 2 +- Misc/NEWS | 4 - Python/errors.c | 25 +- Python/import.c | 3 +- Python/importlib.h | 1589 +++++++++++----------- 10 files changed, 808 insertions(+), 843 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -292,13 +292,6 @@ .. versionadded:: 3.3 -.. c:function:: PyObject* PyErr_SetImportErrorSubclass(PyObject *msg, PyObject *name, PyObject *path) - - Much like :c:func:`PyErr_SetImportError` but this function allows for - specifying a subclass of :exc:`ImportError` to raise. - - .. versionadded:: 3.4 - .. c:function:: void PyErr_SyntaxLocationEx(char *filename, int lineno, int col_offset) diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -185,8 +185,7 @@ A subclass of :exc:`ImportError` which is raised by :keyword:`import` when a module could not be located. This includes ``from ... import`` statements as the specific attribute being requested cannot be known a priori to be a module - or some other type of object. It is also raised when ``None`` is found in - :data:`sys.modules`. + or some other type of object. .. versionadded:: 3.4 diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -37,7 +37,7 @@ When a module is first imported, Python searches for the module and if found, it creates a module object [#fnmo]_, initializing it. If the named module -cannot be found, an :exc:`ModuleNotFoundError` is raised. Python implements various +cannot be found, an :exc:`ImportError` is raised. Python implements various strategies to search for the named module when the import machinery is invoked. These strategies can be modified and extended by using various hooks described in the sections below. @@ -168,7 +168,7 @@ This name will be used in various phases of the import search, and it may be the dotted path to a submodule, e.g. ``foo.bar.baz``. In this case, Python first tries to import ``foo``, then ``foo.bar``, and finally ``foo.bar.baz``. -If any of the intermediate imports fail, an :exc:`ModuleNotFoundError` is raised. +If any of the intermediate imports fail, an :exc:`ImportError` is raised. The module cache @@ -187,7 +187,7 @@ During import, the module name is looked up in :data:`sys.modules` and if present, the associated value is the module satisfying the import, and the process completes. However, if the value is ``None``, then an -:exc:`ModuleNotFoundError` is raised. If the module name is missing, Python will +:exc:`ImportError` is raised. If the module name is missing, Python will continue searching for the module. :data:`sys.modules` is writable. Deleting a key may not destroy the @@ -195,7 +195,7 @@ but it will invalidate the cache entry for the named module, causing Python to search anew for the named module upon its next import. The key can also be assigned to ``None``, forcing the next import -of the module to result in an :exc:`ModuleNotFoundError`. +of the module to result in an :exc:`ImportError`. Beware though, as if you keep a reference to the module object, invalidate its cache entry in :data:`sys.modules`, and then re-import the @@ -284,7 +284,7 @@ If the meta path finder knows how to handle the named module, it returns a loader object. If it cannot handle the named module, it returns ``None``. If :data:`sys.meta_path` processing reaches the end of its list without returning -a loader, then an :exc:`ModuleNotFoundError` is raised. Any other exceptions raised +a loader, then an :exc:`ImportError` is raised. Any other exceptions raised are simply propagated up, aborting the import process. The :meth:`find_module()` method of meta path finders is called with two @@ -647,7 +647,7 @@ To selectively prevent import of some modules from a hook early on the meta path (rather than disabling the standard import system entirely), -it is sufficient to raise :exc:`ModuleNotFoundError` directly from +it is sufficient to raise :exc:`ImportError` directly from :meth:`find_module` instead of returning ``None``. The latter indicates that the meta path search should continue. while raising an exception terminates it immediately. 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 @@ -312,7 +312,8 @@ using ``hasattr(module, '__path__')``. * :c:func:`PyErr_SetImportError` now sets :exc:`TypeError` when its **msg** - argument is not set. Previously only ``NULL`` was returned. + argument is not set. Previously only ``NULL`` was returned with no exception + set. * :func:`py_compile.compile` now raises :exc:`FileExistsError` if the file path it would write to is a symlink or a non-regular file. This is to act as a diff --git a/Include/pyerrors.h b/Include/pyerrors.h --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -268,9 +268,6 @@ PyAPI_FUNC(PyObject *) PyErr_SetExcWithArgsKwargs(PyObject *, PyObject *, PyObject *); - -PyAPI_FUNC(PyObject *) PyErr_SetImportErrorSubclass(PyObject *, PyObject *, - PyObject *, PyObject *); PyAPI_FUNC(PyObject *) PyErr_SetImportError(PyObject *, PyObject *, PyObject *); diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1617,7 +1617,7 @@ _imp.release_lock() message = ("import of {} halted; " "None in sys.modules".format(name)) - raise ModuleNotFoundError(message, name=name) + raise ImportError(message, name=name) _lock_unlock_module(name) return module diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -539,10 +539,6 @@ C-API ----- -- Issue #15767: Added PyErr_SetImportErrorSubclass(). - -- PyErr_SetImportError() now sets TypeError when its msg argument is set. - - 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. diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -619,25 +619,12 @@ #endif /* MS_WINDOWS */ PyObject * -PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, - PyObject *name, PyObject *path) +PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) { - int issubclass; PyObject *args, *kwargs, *error; - issubclass = PyObject_IsSubclass(exception, PyExc_ImportError); - if (issubclass < 0) { + if (msg == NULL) return NULL; - } - else if (!issubclass) { - PyErr_SetString(PyExc_TypeError, "expected a subclass of ImportError"); - return NULL; - } - - if (msg == NULL) { - PyErr_SetString(PyExc_TypeError, "expected a message argument"); - return NULL; - } args = PyTuple_New(1); if (args == NULL) @@ -662,7 +649,7 @@ PyDict_SetItemString(kwargs, "name", name); PyDict_SetItemString(kwargs, "path", path); - error = PyObject_Call(exception, args, kwargs); + error = PyObject_Call(PyExc_ImportError, args, kwargs); if (error != NULL) { PyErr_SetObject((PyObject *)Py_TYPE(error), error); Py_DECREF(error); @@ -674,12 +661,6 @@ return NULL; } -PyObject * -PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) -{ - return PyErr_SetImportErrorSubclass(PyExc_ImportError, msg, name, path); -} - void _PyErr_BadInternalCall(const char *filename, int lineno) { diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1428,8 +1428,7 @@ PyObject *msg = PyUnicode_FromFormat("import of %R halted; " "None in sys.modules", abs_name); if (msg != NULL) { - PyErr_SetImportErrorSubclass(PyExc_ModuleNotFoundError, msg, - abs_name, NULL); + PyErr_SetImportError(msg, abs_name, NULL); Py_DECREF(msg); } mod = NULL; 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 Jul 5 00:16:36 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 5 Jul 2013 00:16:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315767=3A_back_out?= =?utf-8?q?_8a0ed9f63c6e=2C_finishing_the_removal_of?= Message-ID: <3bmYSN3sZhz7Lnt@mail.python.org> http://hg.python.org/cpython/rev/ee9662d77ebb changeset: 84445:ee9662d77ebb user: Brett Cannon date: Thu Jul 04 17:51:50 2013 -0400 summary: Issue #15767: back out 8a0ed9f63c6e, finishing the removal of ModuleNotFoundError. files: Doc/c-api/exceptions.rst | 2 - Doc/library/exceptions.rst | 13 +- Doc/whatsnew/3.4.rst | 3 - Include/pyerrors.h | 1 - Lib/importlib/_bootstrap.py | 15 +- Lib/pydoc.py | 2 +- Lib/test/exception_hierarchy.txt | 1 - Lib/test/test_exceptions.py | 3 + Lib/test/test_import.py | 25 +- Lib/test/test_importlib/import_/test_api.py | 4 - Lib/test/test_importlib/import_/test_fromlist.py | 8 +- Lib/test/test_pydoc.py | 2 +- Lib/test/test_site.py | 2 +- Misc/NEWS | 3 - Objects/exceptions.c | 9 - Python/ceval.c | 2 +- Python/importlib.h | 744 +++++---- 17 files changed, 412 insertions(+), 427 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -686,8 +686,6 @@ +-----------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_ImportError` | :exc:`ImportError` | | +-----------------------------------------+---------------------------------+----------+ -| :c:data:`PyExc_ModuleNotFoundError` | :exc:`ModuleNotFoundError` | | -+-----------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_IndexError` | :exc:`IndexError` | | +-----------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_InterruptedError` | :exc:`InterruptedError` | | diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -169,8 +169,8 @@ .. exception:: ImportError - Raised when the :keyword:`import` statement has troubles trying to load a - module. + Raised when an :keyword:`import` statement fails to find the module definition + or when a ``from ... import`` fails to find a name that is to be imported. The :attr:`name` and :attr:`path` attributes can be set using keyword-only arguments to the constructor. When set they represent the name of the module @@ -180,15 +180,6 @@ .. versionchanged:: 3.3 Added the :attr:`name` and :attr:`path` attributes. -.. exception:: ModuleNotFoundError - - A subclass of :exc:`ImportError` which is raised by :keyword:`import` when a - module could not be located. This includes ``from ... import`` statements as - the specific attribute being requested cannot be known a priori to be a module - or some other type of object. - - .. versionadded:: 3.4 - .. exception:: IndexError 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 @@ -137,9 +137,6 @@ * Unicode database updated to UCD version 6.2. -* Import now raises the new exception :exc:`ModuleNotFoundError` (subclass of - :exc:`ImportError`) when it cannot find something. - * :func:`min` and :func:`max` now accept a *default* argument that can be used to specify the value they return if the iterable they are evaluating has no elements. Contributed by Julian Berman in :issue:`18111`. diff --git a/Include/pyerrors.h b/Include/pyerrors.h --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -152,7 +152,6 @@ PyAPI_DATA(PyObject *) PyExc_FloatingPointError; PyAPI_DATA(PyObject *) PyExc_OSError; PyAPI_DATA(PyObject *) PyExc_ImportError; -PyAPI_DATA(PyObject *) PyExc_ModuleNotFoundError; PyAPI_DATA(PyObject *) PyExc_IndexError; PyAPI_DATA(PyObject *) PyExc_KeyError; PyAPI_DATA(PyObject *) PyExc_KeyboardInterrupt; diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1556,7 +1556,11 @@ raise ImportError(msg, name=name) loader = _find_module(name, path) if loader is None: - raise ModuleNotFoundError(_ERR_MSG.format(name), name=name) + exc = ImportError(_ERR_MSG.format(name), name=name) + # TODO(brett): switch to a proper ModuleNotFound exception in Python + # 3.4. + exc._not_found = True + raise exc elif name not in sys.modules: # The parent import may have already imported this module. loader.load_module(name) @@ -1642,12 +1646,15 @@ from_name = '{}.{}'.format(module.__name__, x) try: _call_with_frames_removed(import_, from_name) - except ModuleNotFoundError as exc: + except ImportError as exc: # Backwards-compatibility dictates we ignore failed # imports triggered by fromlist for modules that don't # exist. - if exc.name == from_name: - continue + # TODO(brett): In Python 3.4, have import raise + # ModuleNotFound and catch that. + if getattr(exc, '_not_found', False): + if exc.name == from_name: + continue raise return module diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -316,7 +316,7 @@ elif exc is SyntaxError: # A SyntaxError occurred before we could execute the module. raise ErrorDuringImport(value.filename, info) - elif issubclass(exc, ImportError) and value.name == path: + elif exc is ImportError and value.name == path: # No such module in the path. return None else: diff --git a/Lib/test/exception_hierarchy.txt b/Lib/test/exception_hierarchy.txt --- a/Lib/test/exception_hierarchy.txt +++ b/Lib/test/exception_hierarchy.txt @@ -13,7 +13,6 @@ +-- BufferError +-- EOFError +-- ImportError - +-- ModuleNotFoundError +-- LookupError | +-- IndexError | +-- KeyError diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -953,5 +953,8 @@ self.assertEqual(str(arg), str(exc)) +def test_main(): + run_unittest(ExceptionTests, ImportErrorTests) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -68,15 +68,7 @@ def tearDown(self): unload(TESTFN) - def test_import_raises_ModuleNotFoundError(self): - with self.assertRaises(ModuleNotFoundError): - import something_that_should_not_exist_anywhere - - def test_from_import_raises_ModuleNotFoundError(self): - with self.assertRaises(ModuleNotFoundError): - from something_that_should_not_exist_anywhere import blah - with self.assertRaises(ModuleNotFoundError): - from importlib import something_that_should_not_exist_anywhere + setUp = tearDown def test_case_sensitivity(self): # Brief digression to test that import is case-sensitive: if we got @@ -495,7 +487,7 @@ header = f.read(12) code = marshal.load(f) constants = list(code.co_consts) - foreign_code = importlib.import_module.__code__ + foreign_code = test_main.__code__ pos = constants.index(1) constants[pos] = foreign_code code = type(code)(code.co_argcount, code.co_kwonlyargcount, @@ -1021,5 +1013,16 @@ importlib.SourceLoader.load_module = old_load_module +def test_main(verbose=None): + run_unittest(ImportTests, PycacheTests, FilePermissionTests, + PycRewritingTests, PathsTests, RelativeImportTests, + OverridingImportBuiltinTests, + ImportlibBootstrapTests, + TestSymbolicallyLinkedPackage, + ImportTracebackTests) + + if __name__ == '__main__': - unittest.main() + # Test needs to be a package, so we can do relative imports. + from test.test_import import test_main + test_main() diff --git a/Lib/test/test_importlib/import_/test_api.py b/Lib/test/test_importlib/import_/test_api.py --- a/Lib/test/test_importlib/import_/test_api.py +++ b/Lib/test/test_importlib/import_/test_api.py @@ -22,10 +22,6 @@ """Test API-specific details for __import__ (e.g. raising the right exception when passing in an int for the module name).""" - def test_raises_ModuleNotFoundError(self): - with self.assertRaises(ModuleNotFoundError): - util.import_('some module that does not exist') - def test_name_requires_rparition(self): # Raise TypeError if a non-string is passed in for the module name. with self.assertRaises(TypeError): diff --git a/Lib/test/test_importlib/import_/test_fromlist.py b/Lib/test/test_importlib/import_/test_fromlist.py --- a/Lib/test/test_importlib/import_/test_fromlist.py +++ b/Lib/test/test_importlib/import_/test_fromlist.py @@ -68,16 +68,16 @@ self.assertTrue(hasattr(module, 'module')) self.assertEqual(module.module.__name__, 'pkg.module') - def test_module_from_package_triggers_ModuleNotFoundError(self): - # If a submodule causes an ModuleNotFoundError because it tries to import - # a module which doesn't exist, that should let the ModuleNotFoundError + def test_module_from_package_triggers_ImportError(self): + # If a submodule causes an ImportError because it tries to import + # a module which doesn't exist, that should let the ImportError # propagate. def module_code(): import i_do_not_exist with util.mock_modules('pkg.__init__', 'pkg.mod', module_code={'pkg.mod': module_code}) as importer: with util.import_state(meta_path=[importer]): - with self.assertRaises(ModuleNotFoundError) as exc: + with self.assertRaises(ImportError) as exc: import_util.import_('pkg', fromlist=['mod']) self.assertEqual('i_do_not_exist', exc.exception.name) 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 @@ -206,7 +206,7 @@ missing_pattern = "no Python documentation found for '%s'" # output pattern for module with bad imports -badimport_pattern = "problem in %s - ModuleNotFoundError: No module named %r" +badimport_pattern = "problem in %s - ImportError: No module named %r" def run_pydoc(module_name, *args, **env): """ diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -131,7 +131,7 @@ re.escape(os.path.join(pth_dir, pth_fn))) # XXX: ditto previous XXX comment. self.assertRegex(err_out.getvalue(), 'Traceback') - self.assertRegex(err_out.getvalue(), 'ModuleNotFoundError') + self.assertRegex(err_out.getvalue(), 'ImportError') @unittest.skipIf(sys.platform == "win32", "Windows does not raise an " "error for file paths containing null characters") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,9 +25,6 @@ - Issue #18137: Detect integer overflow on precision in float.__format__() and complex.__format__(). -- Issue #15767: Introduce ModuleNotFoundError which is raised when a module - could not be found. - - Issue #18183: Fix various unicode operations on strings with large unicode codepoints. diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -710,13 +710,6 @@ "module."); /* - * ModuleNotFoundError extends ImportError - */ - -MiddlingExtendsException(PyExc_ImportError, ModuleNotFoundError, ImportError, - "Module not found."); - -/* * OSError extends Exception */ @@ -2402,7 +2395,6 @@ PRE_INIT(SystemExit) PRE_INIT(KeyboardInterrupt) PRE_INIT(ImportError) - PRE_INIT(ModuleNotFoundError) PRE_INIT(OSError) PRE_INIT(EOFError) PRE_INIT(RuntimeError) @@ -2473,7 +2465,6 @@ POST_INIT(SystemExit) POST_INIT(KeyboardInterrupt) POST_INIT(ImportError) - POST_INIT(ModuleNotFoundError) POST_INIT(OSError) INIT_ALIAS(EnvironmentError, OSError) INIT_ALIAS(IOError, OSError) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4588,7 +4588,7 @@ x = PyObject_GetAttr(v, name); if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Format(PyExc_ModuleNotFoundError, "cannot import name %S", name); + PyErr_Format(PyExc_ImportError, "cannot import name %S", name); } return x; } 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 Jul 5 00:16:37 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 5 Jul 2013 00:16:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_test=5Fimport_over_to?= =?utf-8?b?IHVuaXR0ZXN0Lm1haW4oKS4=?= Message-ID: <3bmYSP5jJVz7LqS@mail.python.org> http://hg.python.org/cpython/rev/200b1a099ed8 changeset: 84446:200b1a099ed8 user: Brett Cannon date: Thu Jul 04 18:03:57 2013 -0400 summary: Move test_import over to unittest.main(). files: Lib/test/test_import.py | 16 ++-------------- 1 files changed, 2 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -68,8 +68,6 @@ def tearDown(self): unload(TESTFN) - setUp = tearDown - def test_case_sensitivity(self): # Brief digression to test that import is case-sensitive: if we got # this far, we know for sure that "random" exists. @@ -487,7 +485,7 @@ header = f.read(12) code = marshal.load(f) constants = list(code.co_consts) - foreign_code = test_main.__code__ + foreign_code = importlib.import_module.__code__ pos = constants.index(1) constants[pos] = foreign_code code = type(code)(code.co_argcount, code.co_kwonlyargcount, @@ -1013,16 +1011,6 @@ importlib.SourceLoader.load_module = old_load_module -def test_main(verbose=None): - run_unittest(ImportTests, PycacheTests, FilePermissionTests, - PycRewritingTests, PathsTests, RelativeImportTests, - OverridingImportBuiltinTests, - ImportlibBootstrapTests, - TestSymbolicallyLinkedPackage, - ImportTracebackTests) - - if __name__ == '__main__': # Test needs to be a package, so we can do relative imports. - from test.test_import import test_main - test_main() + unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 5 00:16:39 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 5 Jul 2013 00:16:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_dead_code_in_test?= =?utf-8?q?=5Fexceptions=2E?= Message-ID: <3bmYSR0R26z7Lqs@mail.python.org> http://hg.python.org/cpython/rev/6a8ba235542a changeset: 84447:6a8ba235542a user: Brett Cannon date: Thu Jul 04 18:04:20 2013 -0400 summary: Remove dead code in test_exceptions. files: Lib/test/test_exceptions.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -953,8 +953,5 @@ self.assertEqual(str(arg), str(exc)) -def test_main(): - run_unittest(ExceptionTests, ImportErrorTests) - if __name__ == '__main__': unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 5 00:16:40 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 5 Jul 2013 00:16:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315767=3A_Excise_t?= =?utf-8?q?he_remaining_instances_of_ModuleNotFoundError?= Message-ID: <3bmYSS3ddfz7LqV@mail.python.org> http://hg.python.org/cpython/rev/de947db308ba changeset: 84448:de947db308ba user: Brett Cannon date: Thu Jul 04 18:16:15 2013 -0400 summary: Issue #15767: Excise the remaining instances of ModuleNotFoundError files: Lib/stat.py | 2 +- Lib/test/regrtest.py | 16 ++++++++-------- Lib/test/support.py | 16 ++++++++-------- Lib/test/test___all__.py | 2 +- Lib/test/test_tarfile.py | 6 +++--- Lib/test/test_xmlrpc.py | 4 ++-- Lib/xmlrpc/server.py | 2 +- Lib/zipfile.py | 6 +++--- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Lib/stat.py b/Lib/stat.py --- a/Lib/stat.py +++ b/Lib/stat.py @@ -151,5 +151,5 @@ # If available, use C implementation try: from _stat import * -except ModuleNotFoundError: +except ImportError: pass diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -146,11 +146,11 @@ try: import threading -except ModuleNotFoundError: +except ImportError: threading = None try: import multiprocessing.process -except ModuleNotFoundError: +except ImportError: multiprocessing = None @@ -180,7 +180,7 @@ if sys.platform == 'darwin': try: import resource - except ModuleNotFoundError: + except ImportError: pass else: soft, hard = resource.getrlimit(resource.RLIMIT_STACK) @@ -567,7 +567,7 @@ if findleaks: try: import gc - except ModuleNotFoundError: + except ImportError: print('No GC available, disabling findleaks.') findleaks = False else: @@ -688,7 +688,7 @@ if use_mp: try: from threading import Thread - except ModuleNotFoundError: + except ImportError: print("Multiprocess option requires thread support") sys.exit(2) from queue import Queue @@ -1399,7 +1399,7 @@ pic = sys.path_importer_cache.copy() try: import zipimport - except ModuleNotFoundError: + except ImportError: zdc = None # Run unmodified on platforms without zipimport support else: zdc = zipimport._zip_directory_cache.copy() @@ -1476,7 +1476,7 @@ sys.path_importer_cache.update(pic) try: import zipimport - except ModuleNotFoundError: + except ImportError: pass # Run unmodified on platforms without zipimport support else: zipimport._zip_directory_cache.clear() @@ -1513,7 +1513,7 @@ doctest.master = None try: import ctypes - except ModuleNotFoundError: + except ImportError: # Don't worry about resetting the cache if ctypes is not supported pass else: diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -29,32 +29,32 @@ try: import _thread, threading -except ModuleNotFoundError: +except ImportError: _thread = None threading = None try: import multiprocessing.process -except ModuleNotFoundError: +except ImportError: multiprocessing = None try: import zlib -except ModuleNotFoundError: +except ImportError: zlib = None try: import gzip -except ModuleNotFoundError: +except ImportError: gzip = None try: import bz2 -except ModuleNotFoundError: +except ImportError: bz2 = None try: import lzma -except ModuleNotFoundError: +except ImportError: lzma = None __all__ = [ @@ -121,7 +121,7 @@ with _ignore_deprecated_imports(deprecated): try: return importlib.import_module(name) - except ModuleNotFoundError as msg: + except ImportError as msg: if sys.platform.startswith(tuple(required_on)): raise raise unittest.SkipTest(str(msg)) @@ -193,7 +193,7 @@ if not _save_and_block_module(blocked_name, orig_modules): names_to_remove.append(blocked_name) fresh_module = importlib.import_module(name) - except ModuleNotFoundError: + except ImportError: fresh_module = None finally: for orig_name, module in orig_modules.items(): diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -75,7 +75,7 @@ try: import rlcompleter import locale - except ModuleNotFoundError: + except ImportError: pass else: locale.setlocale(locale.LC_CTYPE, 'C') 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 @@ -12,15 +12,15 @@ # Check for our compression modules. try: import gzip -except ModuleNotFoundError: +except ImportError: gzip = None try: import bz2 -except ModuleNotFoundError: +except ImportError: bz2 = None try: import lzma -except ModuleNotFoundError: +except ImportError: lzma = None def md5sum(data): diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -15,11 +15,11 @@ try: import gzip -except ModuleNotFoundError: +except ImportError: gzip = None try: import threading -except ModuleNotFoundError: +except ImportError: threading = None alist = [{'astring': 'foo at bar.baz.spam', diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -116,7 +116,7 @@ import traceback try: import fcntl -except ModuleNotFoundError: +except ImportError: fcntl = None def resolve_dotted_attribute(obj, attr, allow_dotted_names=True): diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -18,18 +18,18 @@ try: import zlib # We may need its compression method crc32 = zlib.crc32 -except ModuleNotFoundError: +except ImportError: zlib = None crc32 = binascii.crc32 try: import bz2 # We may need its compression method -except ModuleNotFoundError: +except ImportError: bz2 = None try: import lzma # We may need its compression method -except ModuleNotFoundError: +except ImportError: lzma = None __all__ = ["BadZipFile", "BadZipfile", "error", -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 5 01:41:51 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 5 Jul 2013 01:41:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzQ3?= =?utf-8?q?=3A_ElementTree=27s_html_serializer_now_preserves_the_case_of_c?= =?utf-8?q?losing?= Message-ID: <3bmbLl2xcsz7Lk2@mail.python.org> http://hg.python.org/cpython/rev/df79735b21c1 changeset: 84449:df79735b21c1 branch: 3.3 parent: 84438:b3ea1b5a1617 user: Christian Heimes date: Fri Jul 05 01:39:49 2013 +0200 summary: Issue #18347: ElementTree's html serializer now preserves the case of closing tags. files: Lib/test/test_xml_etree.py | 7 +++++++ Lib/xml/etree/ElementTree.py | 6 +++--- Misc/NEWS | 3 +++ 3 files changed, 13 insertions(+), 3 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 @@ -751,6 +751,13 @@ '\n') self.assertEqual(serialize(e, method="text"), '1 < 2\n') + def test_issue18347(self): + e = ET.XML('text') + self.assertEqual(serialize(e), + 'text') + self.assertEqual(serialize(e, method="html"), + 'text') + def test_entity(self): # Test entity handling. 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 @@ -1039,15 +1039,15 @@ # FIXME: handle boolean attributes write(" %s=\"%s\"" % (qnames[k], v)) write(">") - tag = tag.lower() + ltag = tag.lower() if text: - if tag == "script" or tag == "style": + if ltag == "script" or ltag == "style": write(text) else: write(_escape_cdata(text)) for e in elem: _serialize_html(write, e, qnames, None) - if tag not in HTML_EMPTY: + if ltag not in HTML_EMPTY: write("") if elem.tail: write(_escape_cdata(elem.tail)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -41,6 +41,9 @@ Library ------- +- Issue #18347: ElementTree's html serializer now preserves the case of + closing tags. + - Issue #17261: Ensure multiprocessing's proxies use proper address. - Issue #18343: faulthandler.register() now keeps the previous signal handler -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 5 01:41:52 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 5 Jul 2013 01:41:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318347=3A_ElementTree=27s_html_serializer_now_pr?= =?utf-8?q?eserves_the_case_of_closing?= Message-ID: <3bmbLm4xvZz7Ll0@mail.python.org> http://hg.python.org/cpython/rev/d5536c06a082 changeset: 84450:d5536c06a082 parent: 84448:de947db308ba parent: 84449:df79735b21c1 user: Christian Heimes date: Fri Jul 05 01:40:52 2013 +0200 summary: Issue #18347: ElementTree's html serializer now preserves the case of closing tags. files: Lib/test/test_xml_etree.py | 7 +++++++ Lib/xml/etree/ElementTree.py | 6 +++--- Misc/NEWS | 3 +++ 3 files changed, 13 insertions(+), 3 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 @@ -742,6 +742,13 @@ '\n') self.assertEqual(serialize(e, method="text"), '1 < 2\n') + def test_issue18347(self): + e = ET.XML('text') + self.assertEqual(serialize(e), + 'text') + self.assertEqual(serialize(e, method="html"), + 'text') + def test_entity(self): # Test entity handling. 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 @@ -992,15 +992,15 @@ # FIXME: handle boolean attributes write(" %s=\"%s\"" % (qnames[k], v)) write(">") - tag = tag.lower() + ltag = tag.lower() if text: - if tag == "script" or tag == "style": + if ltag == "script" or ltag == "style": write(text) else: write(_escape_cdata(text)) for e in elem: _serialize_html(write, e, qnames, None) - if tag not in HTML_EMPTY: + if ltag not in HTML_EMPTY: write("") if elem.tail: write(_escape_cdata(elem.tail)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -135,6 +135,9 @@ Library ------- +- Issue #18347: ElementTree's html serializer now preserves the case of + closing tags. + - Issue #17261: Ensure multiprocessing's proxies use proper address. - Issue #18343: faulthandler.register() now keeps the previous signal handler -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 5 01:41:53 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 5 Jul 2013 01:41:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MzQ3?= =?utf-8?q?=3A_ElementTree=27s_html_serializer_now_preserves_the_case_of_c?= =?utf-8?q?losing?= Message-ID: <3bmbLn6ztLz7Lmp@mail.python.org> http://hg.python.org/cpython/rev/328781ae35d2 changeset: 84451:328781ae35d2 branch: 2.7 parent: 84441:e3fd5fc5dc47 user: Christian Heimes date: Fri Jul 05 01:41:30 2013 +0200 summary: Issue #18347: ElementTree's html serializer now preserves the case of closing tags. files: Lib/test/test_xml_etree.py | 10 ++++++++++ Lib/xml/etree/ElementTree.py | 6 +++--- Misc/NEWS | 3 +++ 3 files changed, 16 insertions(+), 3 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 @@ -1769,6 +1769,16 @@ """ +def bug_18347(): + """ + + >>> e = ET.XML('text') + >>> serialize(e) + 'text' + >>> serialize(e, method="html") + 'text' + """ + # -------------------------------------------------------------------- # reported on bugs.python.org 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 @@ -988,15 +988,15 @@ # FIXME: handle boolean attributes write(" %s=\"%s\"" % (qnames[k], v)) write(">") - tag = tag.lower() + ltag = tag.lower() if text: - if tag == "script" or tag == "style": + if ltag == "script" or ltag == "style": write(_encode(text, encoding)) else: write(_escape_cdata(text, encoding)) for e in elem: _serialize_html(write, e, encoding, qnames, None) - if tag not in HTML_EMPTY: + if ltag not in HTML_EMPTY: write("") if elem.tail: write(_escape_cdata(elem.tail, encoding)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #18347: ElementTree's html serializer now preserves the case of + closing tags. + - Issue #17261: Ensure multiprocessing's proxies use proper address. - Issue #17097: Make multiprocessing ignore EINTR. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 5 05:43:59 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 05 Jul 2013 05:43:59 +0200 Subject: [Python-checkins] Daily reference leaks (d5536c06a082): sum=0 Message-ID: results for d5536c06a082 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogZ7wEhS', '-x'] From solipsis at pitrou.net Sat Jul 6 05:43:24 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 06 Jul 2013 05:43:24 +0200 Subject: [Python-checkins] Daily reference leaks (d5536c06a082): sum=2 Message-ID: results for d5536c06a082 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/reflogWCNA5b', '-x'] From python-checkins at python.org Sat Jul 6 06:06:03 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 6 Jul 2013 06:06:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Speed-up_deque_indexing_by?= =?utf-8?q?_changing_the_deque_block_length_to_a_power_of_two=2E?= Message-ID: <3bnK9706nkz7Lk2@mail.python.org> http://hg.python.org/cpython/rev/6d278f426417 changeset: 84452:6d278f426417 parent: 84450:d5536c06a082 user: Raymond Hettinger date: Fri Jul 05 18:05:29 2013 -1000 summary: Speed-up deque indexing by changing the deque block length to a power of two. The division and modulo calculation in deque_item() can be compiled to fast bitwise operations when the BLOCKLEN is a power of two. Timing before: ~/cpython $ py -m timeit -r7 -s 'from collections import deque' -s 'd=deque(range(10))' 'd[5]' 10000000 loops, best of 7: 0.0627 usec per loop Timing after: ~/cpython $ py -m timeit -r7 -s 'from collections import deque' -s 'd=deque(range(10))' 'd[5]' 10000000 loops, best of 7: 0.0581 usec per loop files: Lib/test/test_deque.py | 2 +- Modules/_collectionsmodule.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -536,7 +536,7 @@ @support.cpython_only def test_sizeof(self): - BLOCKLEN = 62 + BLOCKLEN = 64 basesize = support.calcobjsize('2P4nlP') blocksize = struct.calcsize('2P%dP' % BLOCKLEN) self.assertEqual(object.__sizeof__(deque()), basesize) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -14,7 +14,7 @@ * division/modulo computations during indexing. */ -#define BLOCKLEN 62 +#define BLOCKLEN 64 #define CENTER ((BLOCKLEN - 1) / 2) /* A `dequeobject` is composed of a doubly-linked list of `block` nodes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 10:25:19 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sat, 6 Jul 2013 10:25:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3ODYw?= =?utf-8?q?=3A_explicitly_mention_that_std*_streams_are_opened_in_binary_m?= =?utf-8?q?ode_by?= Message-ID: <3bnQwH1z6Vz7LjW@mail.python.org> http://hg.python.org/cpython/rev/a2c2ffa1a41c changeset: 84453:a2c2ffa1a41c branch: 3.3 parent: 84449:df79735b21c1 user: Ronald Oussoren date: Sat Jul 06 10:23:59 2013 +0200 summary: Issue #17860: explicitly mention that std* streams are opened in binary mode by default. The documentation does mention that the streams are opened in text mode when univeral_newlines is true, but not that that they are opened in binary mode when that argument is false and that seems to confuse at least some users. files: Doc/library/subprocess.rst | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -293,7 +293,8 @@ If *universal_newlines* is ``True``, the file objects *stdin*, *stdout* and *stderr* will be opened as text streams in :term:`universal newlines` mode using the encoding returned by :func:`locale.getpreferredencoding(False) - `. For *stdin*, line ending characters + `, otherwise these streams will be opened + as binary streams. For *stdin*, line ending characters ``'\n'`` in the input will be converted to the default line separator :data:`os.linesep`. For *stdout* and *stderr*, all line endings in the output will be converted to ``'\n'``. For more information see the @@ -537,7 +538,8 @@ If *universal_newlines* is ``True``, the file objects *stdin*, *stdout* and *stderr* are opened as text streams in universal newlines mode, as - described above in :ref:`frequently-used-arguments`. + described above in :ref:`frequently-used-arguments`, otherwise they are + opened as binary streams. If given, *startupinfo* will be a :class:`STARTUPINFO` object, which is passed to the underlying ``CreateProcess`` function. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 10:25:20 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sat, 6 Jul 2013 10:25:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=283=2E3-=3Edefault=29_Issue_=2317860=3A_explicitly_ment?= =?utf-8?q?ion_that_std*_streams_are_opened_in?= Message-ID: <3bnQwJ3szqz7LjW@mail.python.org> http://hg.python.org/cpython/rev/ae8b054155c1 changeset: 84454:ae8b054155c1 parent: 84452:6d278f426417 parent: 84453:a2c2ffa1a41c user: Ronald Oussoren date: Sat Jul 06 10:25:04 2013 +0200 summary: (3.3->default) Issue #17860: explicitly mention that std* streams are opened in binary mode by default. The documentation does mention that the streams are opened in text mode when univeral_newlines is true, but not that that they are opened in binary mode when that argument is false and that seems to confuse at least some users. files: Doc/library/subprocess.rst | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -303,7 +303,8 @@ If *universal_newlines* is ``True``, the file objects *stdin*, *stdout* and *stderr* will be opened as text streams in :term:`universal newlines` mode using the encoding returned by :func:`locale.getpreferredencoding(False) - `. For *stdin*, line ending characters + `, otherwise these streams will be opened + as binary streams. For *stdin*, line ending characters ``'\n'`` in the input will be converted to the default line separator :data:`os.linesep`. For *stdout* and *stderr*, all line endings in the output will be converted to ``'\n'``. For more information see the @@ -547,7 +548,8 @@ If *universal_newlines* is ``True``, the file objects *stdin*, *stdout* and *stderr* are opened as text streams in universal newlines mode, as - described above in :ref:`frequently-used-arguments`. + described above in :ref:`frequently-used-arguments`, otherwise they are + opened as binary streams. If given, *startupinfo* will be a :class:`STARTUPINFO` object, which is passed to the underlying ``CreateProcess`` function. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 12:28:13 2013 From: python-checkins at python.org (florent.xicluna) Date: Sat, 6 Jul 2013 12:28:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4Mzc1?= =?utf-8?q?=3A_Assume_--randomize_when_--randseed_is_used_for_running_the?= Message-ID: <3bnTf535D1z7Lk0@mail.python.org> http://hg.python.org/cpython/rev/5bd3f9ed357e changeset: 84455:5bd3f9ed357e branch: 3.3 parent: 84453:a2c2ffa1a41c user: Florent Xicluna date: Sat Jul 06 12:25:52 2013 +0200 summary: Issue #18375: Assume --randomize when --randseed is used for running the testsuite. files: Lib/test/regrtest.py | 1 + Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -346,6 +346,7 @@ elif o in ('-r', '--randomize'): randomize = True elif o == '--randseed': + randomize = True random_seed = int(a) elif o in ('-f', '--fromfile'): fromfile = a diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -158,6 +158,9 @@ Tests ----- +- Issue #18375: Assume --randomize when --randseed is used for running the + testsuite. + - Issue #11185: Fix test_wait4 under AIX. Patch by S?bastien Sabl?. - Issue #17691: test_univnewlines now works with unittest test discovery. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 12:28:14 2013 From: python-checkins at python.org (florent.xicluna) Date: Sat, 6 Jul 2013 12:28:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318375=3A_merge_with_3=2E3?= Message-ID: <3bnTf654BWz7LmK@mail.python.org> http://hg.python.org/cpython/rev/7be081fa8db1 changeset: 84456:7be081fa8db1 parent: 84454:ae8b054155c1 parent: 84455:5bd3f9ed357e user: Florent Xicluna date: Sat Jul 06 12:27:50 2013 +0200 summary: Issue #18375: merge with 3.3 files: Lib/test/regrtest.py | 1 + Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -428,6 +428,7 @@ elif o in ('-r', '--randomize'): randomize = True elif o == '--randseed': + randomize = True random_seed = int(a) elif o in ('-f', '--fromfile'): fromfile = a diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -468,6 +468,9 @@ Tests ----- +- Issue #18375: Assume --randomize when --randseed is used for running the + testsuite. + - Issue #11185: Fix test_wait4 under AIX. Patch by S?bastien Sabl?. - Issue #18207: Fix test_ssl for some versions of OpenSSL that ignore seconds -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 13:20:27 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sat, 6 Jul 2013 13:20:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyOTkw?= =?utf-8?q?=3A_The_=22Python_Launcher=22_on_OSX_could_not_launch_python_sc?= =?utf-8?q?ripts_that?= Message-ID: <3bnVpM5lnTz7LmX@mail.python.org> http://hg.python.org/cpython/rev/7ec9255d4189 changeset: 84457:7ec9255d4189 branch: 2.7 parent: 84451:328781ae35d2 user: Ronald Oussoren date: Sat Jul 06 13:19:58 2013 +0200 summary: Issue #12990: The "Python Launcher" on OSX could not launch python scripts that have paths that include wide characters. files: Mac/PythonLauncher/MyDocument.m | 2 +- Misc/NEWS | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m --- a/Mac/PythonLauncher/MyDocument.m +++ b/Mac/PythonLauncher/MyDocument.m @@ -76,7 +76,7 @@ const char *cmdline; int sts; - cmdline = [[settings commandLineForScript: script] cString]; + cmdline = [[settings commandLineForScript: script] UTF8String]; if ([settings with_terminal]) { sts = doscript(cmdline); } else { diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -67,6 +67,12 @@ - Issue #18113: Fixed a refcount leak in the curses.panel module's set_userptr() method. Reported by Atsuo Ishimoto. +Tools/Demos +----------- + +- Issue #12990: The "Python Launcher" on OSX could not launch python scripts + that have paths that include wide characters. + Build ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 13:26:12 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sat, 6 Jul 2013 13:26:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzEyOTkw?= =?utf-8?q?=3A_The_=22Python_Launcher=22_on_OSX_could_not_launch_python_sc?= =?utf-8?q?ripts_that?= Message-ID: <3bnVx041H8z7LkW@mail.python.org> http://hg.python.org/cpython/rev/27eb350d5056 changeset: 84458:27eb350d5056 branch: 3.3 parent: 84455:5bd3f9ed357e user: Ronald Oussoren date: Sat Jul 06 13:20:57 2013 +0200 summary: Issue #12990: The "Python Launcher" on OSX could not launch python scripts that have paths that include wide characters. files: Mac/PythonLauncher/MyDocument.m | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m --- a/Mac/PythonLauncher/MyDocument.m +++ b/Mac/PythonLauncher/MyDocument.m @@ -76,7 +76,7 @@ const char *cmdline; int sts; - cmdline = [[settings commandLineForScript: script] cString]; + cmdline = [[settings commandLineForScript: script] UTF8String]; if ([settings with_terminal]) { sts = doscript(cmdline); } else { diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -188,6 +188,9 @@ - Issue #15239: Make mkstringprep.py work again on Python 3. +- Issue #12990: The "Python Launcher" on OSX could not launch python scripts + that have paths that include wide characters. + Build ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 13:26:13 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sat, 6 Jul 2013 13:26:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogKDMuMy0+ZGVmYXVsdCkgSXNzdWUgIzEyOTkwOiBUaGUgIlB5dGhvbiBM?= =?utf-8?q?auncher=22_on_OSX_could_not_launch?= Message-ID: <3bnVx16LTDz7LmM@mail.python.org> http://hg.python.org/cpython/rev/b6ebc726d5fe changeset: 84459:b6ebc726d5fe parent: 84456:7be081fa8db1 parent: 84458:27eb350d5056 user: Ronald Oussoren date: Sat Jul 06 13:25:44 2013 +0200 summary: (3.3->default) Issue #12990: The "Python Launcher" on OSX could not launch python scripts that have paths that include wide characters. files: Mac/PythonLauncher/MyDocument.m | 2 +- Misc/NEWS | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m --- a/Mac/PythonLauncher/MyDocument.m +++ b/Mac/PythonLauncher/MyDocument.m @@ -76,7 +76,7 @@ const char *cmdline; int sts; - cmdline = [[settings commandLineForScript: script] cString]; + cmdline = [[settings commandLineForScript: script] UTF8String]; if ([settings with_terminal]) { sts = doscript(cmdline); } else { diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -599,6 +599,12 @@ - Issue #15172: Document NASM 2.10+ as requirement for building OpenSSL 1.0.1 on Windows. +Tools/Demos +----------- + +- Issue #12990: The "Python Launcher" on OSX could not launch python scripts + that have paths that include wide characters. + What's New in Python 3.3.1 release candidate 1? =============================================== -- Repository URL: http://hg.python.org/cpython From rdmurray at bitdance.com Sat Jul 6 13:59:07 2013 From: rdmurray at bitdance.com (R. David Murray) Date: Sat, 06 Jul 2013 07:59:07 -0400 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3ODYw?= =?utf-8?q?=3A_explicitly_mention_that_std*_streams_are_opened_in_b?= =?utf-8?q?inary_mode_by?= In-Reply-To: <3bnQwH1z6Vz7LjW@mail.python.org> References: <3bnQwH1z6Vz7LjW@mail.python.org> Message-ID: <20130706115908.2072B250185@webabinitio.net> On Sat, 06 Jul 2013 10:25:19 +0200, ronald.oussoren wrote: > http://hg.python.org/cpython/rev/a2c2ffa1a41c > changeset: 84453:a2c2ffa1a41c > branch: 3.3 > parent: 84449:df79735b21c1 > user: Ronald Oussoren > date: Sat Jul 06 10:23:59 2013 +0200 > summary: > Issue #17860: explicitly mention that std* streams are opened in binary mode by default. > > The documentation does mention that the streams are opened in text mode > when univeral_newlines is true, but not that that they are opened in > binary mode when that argument is false and that seems to confuse at > least some users. > > files: > Doc/library/subprocess.rst | 6 ++++-- > 1 files changed, 4 insertions(+), 2 deletions(-) > > > diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst > --- a/Doc/library/subprocess.rst > +++ b/Doc/library/subprocess.rst > @@ -293,7 +293,8 @@ > If *universal_newlines* is ``True``, the file objects *stdin*, *stdout* and > *stderr* will be opened as text streams in :term:`universal newlines` mode > using the encoding returned by :func:`locale.getpreferredencoding(False) > - `. For *stdin*, line ending characters > + `, otherwise these streams will be opened > + as binary streams. For *stdin*, line ending characters > ``'\n'`` in the input will be converted to the default line separator > :data:`os.linesep`. For *stdout* and *stderr*, all line endings in the > output will be converted to ``'\n'``. For more information see the IMO, either the default should be mentioned first, or the default should be mentioned in a parenthetical. Otherwise it sounds like newline translation is being done in both modes. Logically that makes no sense, so the above construction will likely lead to, at a minimum, an interruption in the flow for the reader, and at worse even more confusion than not mentioning it at all. --David From ronaldoussoren at mac.com Sat Jul 6 14:09:38 2013 From: ronaldoussoren at mac.com (Ronald Oussoren) Date: Sat, 6 Jul 2013 14:09:38 +0200 Subject: [Python-checkins] [Python-Dev] cpython (3.3): Issue #17860: explicitly mention that std* streams are opened in binary mode by In-Reply-To: <20130706115908.2072B250185@webabinitio.net> References: <3bnQwH1z6Vz7LjW@mail.python.org> <20130706115908.2072B250185@webabinitio.net> Message-ID: On 6 Jul, 2013, at 13:59, R. David Murray wrote: > On Sat, 06 Jul 2013 10:25:19 +0200, ronald.oussoren wrote: >> http://hg.python.org/cpython/rev/a2c2ffa1a41c >> changeset: 84453:a2c2ffa1a41c >> branch: 3.3 >> parent: 84449:df79735b21c1 >> user: Ronald Oussoren >> date: Sat Jul 06 10:23:59 2013 +0200 >> summary: >> Issue #17860: explicitly mention that std* streams are opened in binary mode by default. >> >> The documentation does mention that the streams are opened in text mode >> when univeral_newlines is true, but not that that they are opened in >> binary mode when that argument is false and that seems to confuse at >> least some users. >> >> files: >> Doc/library/subprocess.rst | 6 ++++-- >> 1 files changed, 4 insertions(+), 2 deletions(-) >> >> >> diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst >> --- a/Doc/library/subprocess.rst >> +++ b/Doc/library/subprocess.rst >> @@ -293,7 +293,8 @@ >> If *universal_newlines* is ``True``, the file objects *stdin*, *stdout* and >> *stderr* will be opened as text streams in :term:`universal newlines` mode >> using the encoding returned by :func:`locale.getpreferredencoding(False) >> - `. For *stdin*, line ending characters >> + `, otherwise these streams will be opened >> + as binary streams. For *stdin*, line ending characters >> ``'\n'`` in the input will be converted to the default line separator >> :data:`os.linesep`. For *stdout* and *stderr*, all line endings in the >> output will be converted to ``'\n'``. For more information see the > > IMO, either the default should be mentioned first, or the default > should be mentioned in a parenthetical. Otherwise it sounds like > newline translation is being done in both modes. Logically that makes > no sense, so the above construction will likely lead to, at a minimum, > an interruption in the flow for the reader, and at worse even more > confusion than not mentioning it at all. You've got a point there. Converting the next text (", otherwise ...") to a parententical seems to be the cleanest fix, creating a separate sentence for the ``False`` case introduces duplication unless I restructure the text. Ronald > > --David > _______________________________________________ > Python-Dev mailing list > Python-Dev at python.org > http://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: http://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com From python-checkins at python.org Sat Jul 6 14:31:47 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 6 Jul 2013 14:31:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_446=3A_enhance_the_Ration?= =?utf-8?q?ale_to_take_into_account_Cameron_Simpson=27s_remarks?= Message-ID: <3bnXNg74PRz7Ln1@mail.python.org> http://hg.python.org/peps/rev/425f831fddf7 changeset: 4978:425f831fddf7 user: Victor Stinner date: Sat Jul 06 14:27:23 2013 +0200 summary: PEP 446: enhance the Rationale to take into account Cameron Simpson's remarks * mention the name of the close-on-exec flag: HANDLE_FLAG_INHERIT, O_CLOEXEC * mention the name of the blocking flag: O_NONBLOCK * explain that file attributes are duplicated at fork files: pep-0446.txt | 28 +++++++++++++++++++++------- 1 files changed, 21 insertions(+), 7 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -27,14 +27,25 @@ on each file descriptor using a *close-on-exec* flag. By default, the close-on-exec flag is not set. -On Windows, file descriptors are not inherited if the -``bInheritHandles`` parameter of the ``CreateProcess()`` function is -``FALSE``, even if the close-on-exec flag is not set. +On Windows, the close-on-exec flag is ``HANDLE_FLAG_INHERIT``. File +descriptors are not inherited if the ``bInheritHandles`` parameter of +the ``CreateProcess()`` function is ``FALSE``, even if the +``HANDLE_FLAG_INHERIT`` flag is set. If ``bInheritHandles`` is ``TRUE``, +only file descriptors with ``HANDLE_FLAG_INHERIT`` flag set are +inherited, others are not. -On UNIX, file descriptors with the close-and-exec flag set are closed at -the execution of a new program (ex: when calling ``execv()``). The flag -has no effect on ``fork()``, all file descriptors are inherited by the -child process. +On UNIX, the close-on-exec flag is ``O_CLOEXEC``. File descriptors with +the ``O_CLOEXEC`` flag set are closed at the execution of a new program +(ex: when calling ``execv()``). + +The ``O_CLOEXEC`` flag has no effect on ``fork()``, all file descriptors +are inherited by the child process. Futhermore, most properties file +descriptors are shared between the parent and the child processes, +except file attributes which are duplicated (``O_CLOEXEC`` is the only +file attribute). Setting ``O_CLOEXEC`` flag of a file descriptor in the +child process does not change the ``O_CLOEXEC`` flag of the file +descriptor in the parent process. + Issues of the inheritance of file descriptors --------------------------------------------- @@ -62,6 +73,9 @@ By default, newly created sockets are blocking. Setting the non-blocking mode requires additional system calls. +On UNIX, the blocking flag is ``O_NONBLOCK``: a pipe and a socket are +non-blocking if the ``O_NONBLOCK`` flag is set. + Setting flags at the creation of the file descriptor ---------------------------------------------------- -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Jul 6 15:08:51 2013 From: python-checkins at python.org (florent.xicluna) Date: Sat, 6 Jul 2013 15:08:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogdGVzdF9mdHBsaWI6?= =?utf-8?q?_silence_a_BytesWarning_when_checking_TypeError?= Message-ID: <3bnYCR6CJlzRy8@mail.python.org> http://hg.python.org/cpython/rev/851254748c6b changeset: 84460:851254748c6b branch: 3.3 parent: 84458:27eb350d5056 user: Florent Xicluna date: Sat Jul 06 15:08:21 2013 +0200 summary: test_ftplib: silence a BytesWarning when checking TypeError files: Lib/test/test_ftplib.py | 3 ++- 1 files changed, 2 insertions(+), 1 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 @@ -590,7 +590,8 @@ f = io.StringIO(RETR_DATA.replace('\r\n', '\n')) # storlines() expects a binary file, not a text file - self.assertRaises(TypeError, self.client.storlines, 'stor foo', f) + with support.check_warnings(('', BytesWarning), quiet=True): + self.assertRaises(TypeError, self.client.storlines, 'stor foo', f) def test_nlst(self): self.client.nlst() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 15:08:53 2013 From: python-checkins at python.org (florent.xicluna) Date: Sat, 6 Jul 2013 15:08:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_test=5Fftplib=3A_silence_a_BytesWarning_when_checking_Ty?= =?utf-8?q?peError?= Message-ID: <3bnYCT1PFMzRy8@mail.python.org> http://hg.python.org/cpython/rev/dbd301063e59 changeset: 84461:dbd301063e59 parent: 84459:b6ebc726d5fe parent: 84460:851254748c6b user: Florent Xicluna date: Sat Jul 06 15:08:29 2013 +0200 summary: test_ftplib: silence a BytesWarning when checking TypeError files: Lib/test/test_ftplib.py | 3 ++- 1 files changed, 2 insertions(+), 1 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 @@ -591,7 +591,8 @@ f = io.StringIO(RETR_DATA.replace('\r\n', '\n')) # storlines() expects a binary file, not a text file - self.assertRaises(TypeError, self.client.storlines, 'stor foo', f) + with support.check_warnings(('', BytesWarning), quiet=True): + self.assertRaises(TypeError, self.client.storlines, 'stor foo', f) def test_nlst(self): self.client.nlst() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 17:17:57 2013 From: python-checkins at python.org (ezio.melotti) Date: Sat, 6 Jul 2013 17:17:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4MzgwOiBwYXNz?= =?utf-8?q?_regex_flags_to_the_right_argument=2E__Patch_by_Valentina?= Message-ID: <3bnc4P5ZhPzSCt@mail.python.org> http://hg.python.org/cpython/rev/c8fd1351c840 changeset: 84462:c8fd1351c840 branch: 3.3 parent: 84460:851254748c6b user: Ezio Melotti date: Sat Jul 06 17:16:04 2013 +0200 summary: #18380: pass regex flags to the right argument. Patch by Valentina Mukhamedzhanova. files: Lib/email/quoprimime.py | 2 +- Lib/test/test_email/test_email.py | 4 ++++ Misc/ACKS | 1 + 3 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Lib/email/quoprimime.py b/Lib/email/quoprimime.py --- a/Lib/email/quoprimime.py +++ b/Lib/email/quoprimime.py @@ -319,4 +319,4 @@ the high level email.header class for that functionality. """ s = s.replace('_', ' ') - return re.sub(r'=[a-fA-F0-9]{2}', _unquote_match, s, re.ASCII) + return re.sub(r'=[a-fA-F0-9]{2}', _unquote_match, s, flags=re.ASCII) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -4048,6 +4048,10 @@ def test_header_decode_non_ascii(self): self._test_header_decode('hello=C7there', 'hello\xc7there') + def test_header_decode_re_bug_18380(self): + # Issue 18380: Call re.sub with a positional argument for flags in the wrong position + self.assertEqual(quoprimime.header_decode('=30' * 257), '0' * 257) + def _test_decode(self, encoded, expected_decoded, eol=None): if eol is None: decoded = quoprimime.decode(encoded) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -849,6 +849,7 @@ Pablo Mouzo Mher Movsisyan Ruslan Mstoi +Valentina Mukhamedzhanova Michael Mulich Sape Mullender Sjoerd Mullender -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 17:17:59 2013 From: python-checkins at python.org (ezio.melotti) Date: Sat, 6 Jul 2013 17:17:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE4MzgwOiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3bnc4R0pNNz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/6e23ce14c3c6 changeset: 84463:6e23ce14c3c6 parent: 84461:dbd301063e59 parent: 84462:c8fd1351c840 user: Ezio Melotti date: Sat Jul 06 17:17:45 2013 +0200 summary: #18380: merge with 3.3. files: Lib/email/quoprimime.py | 2 +- Lib/test/test_email/test_email.py | 4 ++++ Misc/ACKS | 1 + 3 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Lib/email/quoprimime.py b/Lib/email/quoprimime.py --- a/Lib/email/quoprimime.py +++ b/Lib/email/quoprimime.py @@ -319,4 +319,4 @@ the high level email.header class for that functionality. """ s = s.replace('_', ' ') - return re.sub(r'=[a-fA-F0-9]{2}', _unquote_match, s, re.ASCII) + return re.sub(r'=[a-fA-F0-9]{2}', _unquote_match, s, flags=re.ASCII) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -4048,6 +4048,10 @@ def test_header_decode_non_ascii(self): self._test_header_decode('hello=C7there', 'hello\xc7there') + def test_header_decode_re_bug_18380(self): + # Issue 18380: Call re.sub with a positional argument for flags in the wrong position + self.assertEqual(quoprimime.header_decode('=30' * 257), '0' * 257) + def _test_decode(self, encoded, expected_decoded, eol=None): if eol is None: decoded = quoprimime.decode(encoded) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -871,6 +871,7 @@ Pablo Mouzo Mher Movsisyan Ruslan Mstoi +Valentina Mukhamedzhanova Michael Mulich Sape Mullender Sjoerd Mullender -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 20:48:29 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 6 Jul 2013 20:48:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318364=3A_Stop_usi?= =?utf-8?q?ng_the_ImportError=2E=5Fnot=5Ffound_hack=2E?= Message-ID: <3bnhlK320Wz7Lk0@mail.python.org> http://hg.python.org/cpython/rev/0d590683c8d1 changeset: 84464:0d590683c8d1 user: Brett Cannon date: Sat Jul 06 14:48:18 2013 -0400 summary: Issue #18364: Stop using the ImportError._not_found hack. The private attribute was leaking out of importlib and led to at least one person noticing it. Switch to another hack which won't leak outside of importlib and is nearly as robust. files: Lib/importlib/_bootstrap.py | 13 +- Python/importlib.h | 7136 +++++++++++----------- 2 files changed, 3572 insertions(+), 3577 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1536,7 +1536,8 @@ raise ValueError("Empty module name") -_ERR_MSG = 'No module named {!r}' +_ERR_MSG_PREFIX = 'No module named ' +_ERR_MSG = _ERR_MSG_PREFIX + '{!r}' def _find_and_load_unlocked(name, import_): path = None @@ -1556,11 +1557,7 @@ raise ImportError(msg, name=name) loader = _find_module(name, path) if loader is None: - exc = ImportError(_ERR_MSG.format(name), name=name) - # TODO(brett): switch to a proper ModuleNotFound exception in Python - # 3.4. - exc._not_found = True - raise exc + raise ImportError(_ERR_MSG.format(name), name=name) elif name not in sys.modules: # The parent import may have already imported this module. loader.load_module(name) @@ -1650,9 +1647,7 @@ # Backwards-compatibility dictates we ignore failed # imports triggered by fromlist for modules that don't # exist. - # TODO(brett): In Python 3.4, have import raise - # ModuleNotFound and catch that. - if getattr(exc, '_not_found', False): + if str(exc).startswith(_ERR_MSG_PREFIX): if exc.name == from_name: continue raise diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 21:07:28 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 6 Jul 2013 21:07:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_unnecessary_branche?= =?utf-8?q?s_from_count=28=29_and_reverse=28=29=2E?= Message-ID: <3bnj9D3bTcz7Ljy@mail.python.org> http://hg.python.org/cpython/rev/49a9c734304d changeset: 84465:49a9c734304d user: Raymond Hettinger date: Sat Jul 06 09:07:06 2013 -1000 summary: Remove unnecessary branches from count() and reverse(). files: Modules/_collectionsmodule.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -551,6 +551,8 @@ for (i=0 ; idata[leftindex]; @@ -560,8 +562,6 @@ /* Advance left block/index pair */ leftindex++; if (leftindex == BLOCKLEN) { - if (leftblock->rightlink == NULL) - break; leftblock = leftblock->rightlink; leftindex = 0; } @@ -569,8 +569,6 @@ /* Step backwards with the right block/index pair */ rightindex--; if (rightindex == -1) { - if (rightblock->leftlink == NULL) - break; rightblock = rightblock->leftlink; rightindex = BLOCKLEN - 1; } @@ -594,6 +592,7 @@ int cmp; for (i=0 ; idata[leftindex]; cmp = PyObject_RichCompareBool(item, v, Py_EQ); if (cmp > 0) @@ -610,8 +609,6 @@ /* Advance left block/index pair */ leftindex++; if (leftindex == BLOCKLEN) { - if (leftblock->rightlink == NULL) /* can occur when i==n-1 */ - break; leftblock = leftblock->rightlink; leftindex = 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 6 22:39:00 2013 From: python-checkins at python.org (daniel.holth) Date: Sat, 6 Jul 2013 22:39:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_pep-0426=3A_add_generator_fie?= =?utf-8?q?ld?= Message-ID: <3bnlBr42QhzSfh@mail.python.org> http://hg.python.org/peps/rev/cc4da4be3838 changeset: 4979:cc4da4be3838 user: Daniel Holth date: Sat Jul 06 16:38:22 2013 -0400 summary: pep-0426: add generator field files: pep-0426.txt | 12 ++++++++++++ pep-0426/pymeta-schema.json | 5 +++++ 2 files changed, 17 insertions(+), 0 deletions(-) diff --git a/pep-0426.txt b/pep-0426.txt --- a/pep-0426.txt +++ b/pep-0426.txt @@ -415,6 +415,7 @@ fields: * ``metadata_version`` +* ``generator`` * ``name`` * ``version`` * ``source_label`` @@ -502,6 +503,17 @@ "metadata_version": "2.0" +Generator +--------- + +Name (and optional version) of the program that generated the file, +if any. A manually produced file would omit this field. + +Example:: + + "generator": "setuptools (0.8)" + + Name ---- diff --git a/pep-0426/pymeta-schema.json b/pep-0426/pymeta-schema.json --- a/pep-0426/pymeta-schema.json +++ b/pep-0426/pymeta-schema.json @@ -9,6 +9,11 @@ "type": "string", "pattern": "^(\\d+(\\.\\d+)*)$" }, + "generator": { + "description": "Name and version of the program that produced this file.", + "type": "string", + "pattern": "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])( \\((\\d+(\\.\\d+)*)((a|b|c|rc)(\\d+))?(\\.(post)(\\d+))?(\\.(dev)(\\d+))\\))?$" + }, "name": { "description": "The name of the distribution.", "type": "string", -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Jul 6 22:49:42 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 6 Jul 2013 22:49:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Some_tweaks?= Message-ID: <3bnlRB34LNzNF4@mail.python.org> http://hg.python.org/peps/rev/eddd0a587bd9 changeset: 4980:eddd0a587bd9 user: Antoine Pitrou date: Sat Jul 06 22:48:32 2013 +0200 summary: Some tweaks files: pep-0445.txt | 128 +++++++++++++++++++------------------- 1 files changed, 63 insertions(+), 65 deletions(-) diff --git a/pep-0445.txt b/pep-0445.txt --- a/pep-0445.txt +++ b/pep-0445.txt @@ -13,7 +13,9 @@ ======== This PEP proposes new Application Programming Interfaces (API) to customize -Python memory allocators. +Python memory allocators. The only implementation required to conform to +this PEP is CPython, but other implementations may choose to be compatible, +or to re-use a similar scheme. Rationale @@ -123,11 +125,12 @@ ``PY_SSIZE_T_MAX``. The check is done before calling the inner function. -The *pymalloc* allocator is optimized for objects smaller than 512 bytes -with a short lifetime. It uses memory mappings with a fixed size of 256 -KB called "arenas". +.. note:: + The *pymalloc* allocator is optimized for objects smaller than 512 bytes + with a short lifetime. It uses memory mappings with a fixed size of 256 + KB called "arenas". -Default allocators: +Here is how the allocators are set up by default: * ``PYMEM_DOMAIN_RAW``, ``PYMEM_DOMAIN_MEM``: ``malloc()``, ``realloc()`` and ``free()``; call ``malloc(1)`` when requesting zero @@ -155,11 +158,11 @@ In Python 3.3, the checks are installed by replacing ``PyMem_Malloc()``, ``PyMem_Realloc()``, ``PyMem_Free()``, ``PyObject_Malloc()``, ``PyObject_Realloc()`` and ``PyObject_Free()`` using macros. The new -allocator allocates a larger buffer and write a pattern to detect buffer -underflow, buffer overflow and use after free (fill the buffer with the -pattern ``0xDB``). It uses the original ``PyObject_Malloc()`` +allocator allocates a larger buffer and writes a pattern to detect buffer +underflow, buffer overflow and use after free (by filling the buffer with +the byte ``0xDB``). It uses the original ``PyObject_Malloc()`` function to allocate memory. So ``PyMem_Malloc()`` and -``PyMem_Realloc()`` call indirectly ``PyObject_Malloc()`` and +``PyMem_Realloc()`` indirectly call``PyObject_Malloc()`` and ``PyObject_Realloc()``. This PEP redesigns the debug checks as hooks on the existing allocators @@ -179,7 +182,7 @@ => ``_PyObject_Free()`` As a result, ``PyMem_Malloc()`` and ``PyMem_Realloc()`` now call -``malloc()`` and ``realloc()`` in release mode and in debug mode, +``malloc()`` and ``realloc()`` in both release mode and debug mode, instead of calling ``PyObject_Malloc()`` and ``PyObject_Realloc()`` in debug mode. @@ -199,19 +202,15 @@ Direct calls to ``malloc()`` are replaced with ``PyMem_Malloc()``, or ``PyMem_RawMalloc()`` if the GIL is not held. -Configure external libraries like zlib or OpenSSL to allocate memory +External libraries like zlib or OpenSSL can be configured to allocate memory using ``PyMem_Malloc()`` or ``PyMem_RawMalloc()``. If the allocator of a -library can only be replaced globally, the allocator is not replaced if -Python is embedded in an application. +library can only be replaced globally (rather than on an object-by-object +basis), it shouldn't be replaced when Python is embedded in an application. For the "track memory usage" use case, it is important to track memory allocated in external libraries to have accurate reports, because these -allocations can be large (can raise a ``MemoryError`` exception). - -If an hook is used to the track memory usage, the memory allocated by -direct calls to ``malloc()`` will not be tracked. Remaining ``malloc()`` -in external libraries like OpenSSL or bz2 can allocate large memory -blocks and so would be missed in memory usage reports. +allocations can be large (e.g. they can raise a ``MemoryError`` exception) +and would otherwise be missed in memory usage reports. Examples @@ -282,9 +281,9 @@ Use case 2: Replace Memory Allocators, override pymalloc -------------------------------------------------------- -If your allocator is optimized for allocations of objects smaller than -512 bytes with a short lifetime, pymalloc can be overriden (replace -``PyObject_Malloc()``). +If you have a dedicated allocator optimized for allocations of objects +smaller than 512 bytes with a short lifetime, pymalloc can be overriden +(replace ``PyObject_Malloc()``). Dummy example wasting 2 bytes per memory block:: @@ -420,12 +419,8 @@ More specific functions to get/set memory allocators ---------------------------------------------------- -Replace the 2 functions: - -* ``void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)`` -* ``void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)`` - -with: +It was originally proposed a larger set of C API functions, with one pair +of functions for each allocator domain: * ``void PyMem_GetRawAllocator(PyMemAllocator *allocator)`` * ``void PyMem_GetAllocator(PyMemAllocator *allocator)`` @@ -442,8 +437,8 @@ Make PyMem_Malloc() reuse PyMem_RawMalloc() by default ------------------------------------------------------ -If ``PyMem_Malloc()`` would call ``PyMem_RawMalloc()`` by default, -calling ``PyMem_SetAllocator(PYMEM_DOMAIN_RAW, alloc)`` would also also +If ``PyMem_Malloc()`` called ``PyMem_RawMalloc()`` by default, +calling ``PyMem_SetAllocator(PYMEM_DOMAIN_RAW, alloc)`` would also patch ``PyMem_Malloc()`` indirectly. This alternative was rejected because ``PyMem_SetAllocator()`` would @@ -454,17 +449,17 @@ Add a new PYDEBUGMALLOC environment variable -------------------------------------------- -Add a new ``PYDEBUGMALLOC`` environment variable to enable debug checks -on memory block allocators. The environment variable replaces the new -function ``PyMem_SetupDebugHooks()`` which is not needed anymore. -Another advantage is to allow to enable debug checks even in release -mode: debug checks are always compiled, but only enabled when the -environment variable is present and non-empty. +It was proposed to add a new ``PYDEBUGMALLOC`` environment variable to +enable debug checks on memory block allocators. It would have had the same +effect as calling the ``PyMem_SetupDebugHooks()``, without the need +to write any C code. Another advantage is to allow to enable debug checks +even in release mode: debug checks would always be compiled in, but only +enabled when the environment variable is present and non-empty. This alternative was rejected because a new environment variable would -make the Python initialization even more complex. The `PEP 432 -`_ tries to simply the CPython -startup sequence. +make Python initialization even more complex. `PEP 432 +`_ tries to simplify the +CPython startup sequence. Use macros to get customizable allocators @@ -474,7 +469,7 @@ allocators would be an optional feature enabled by a configuration option or by macros. -This alternative was rejected because the usage of macros implies having +This alternative was rejected because the use of macros implies having to recompile extensions modules to use the new allocator and allocator hooks. Not having to recompile Python nor extension modules makes debug hooks easier to use in practice. @@ -518,12 +513,12 @@ The GC allocator functions would also have to be patched. For example, ``_PyObject_GC_Malloc()`` is used in many C functions and so objects of -differenet types would have the same allocation location. +different types would have the same allocation location. This alternative was rejected because passing a filename and a line number to each allocator makes the API more complex: pass 3 new arguments (ctx, filename, lineno) to each allocator function, instead of -just a context argument (ctx). Having to modify also GC allocator +just a context argument (ctx). Having to also modify GC allocator functions adds too much complexity for a little gain. @@ -531,23 +526,25 @@ ----------------------- In Python 3.3, when Python is compiled in debug mode, ``PyMem_Malloc()`` -calls indirectly ``PyObject_Malloc()`` which requires the GIL to be -held. That's why ``PyMem_Malloc()`` must be called with the GIL held. +indirectly calls ``PyObject_Malloc()`` which requires the GIL to be +held (it isn't thread-safe). That's why ``PyMem_Malloc()`` must be called +with the GIL held. -This PEP changes ``PyMem_Malloc()``: it now always call ``malloc()``. -The "GIL must be held" restriction could be removed from -``PyMem_Malloc()``. +This PEP changes ``PyMem_Malloc()``: it now always calls ``malloc()`` +rather than ``PyObject_Malloc()``. The "GIL must be held" restriction +could therefore be removed from ``PyMem_Malloc()``. This alternative was rejected because allowing to call ``PyMem_Malloc()`` without holding the GIL can break applications which setup their own allocators or allocator hooks. Holding the GIL is -convinient to develop a custom allocator: no need to care of other -threads. It is also convinient for a debug allocator hook: Python -internal objects can be safetly inspected. +convenient to develop a custom allocator: no need to care about other +threads. It is also convenient for a debug allocator hook: Python +objects can be safely inspected, and the C API may be used for reporting. -Calling ``PyGILState_Ensure()`` in -a memory allocator has unexpected behaviour, especially at Python -startup and at creation of a new Python thread state. +Moreover, calling ``PyGILState_Ensure()`` in a memory allocator has +unexpected behaviour, especially at Python startup and when creating of a +new Python thread state. It is better to free custom allocators of +the responsibility of acquiring the GIL. Don't add PyMem_RawMalloc() @@ -566,13 +563,14 @@ for accurate reports of the memory usage. When a debug hook is used to track the memory usage, the memory allocated by direct calls to ``malloc()`` cannot be tracked. ``PyMem_RawMalloc()`` can be hooked and -so all the memory allocated by Python can be tracked. +so all the memory allocated by Python can be tracked, including +memory allocated without holding the GIL. -Use existing debug tools to analyze the memory +Use existing debug tools to analyze memory use ---------------------------------------------- -There are many existing debug tools to analyze the memory. Some +There are many existing debug tools to analyze memory use. Some examples: `Valgrind `_, `Purify `_, `Clang AddressSanitizer `_, `failmalloc @@ -580,14 +578,14 @@ The problem is to retrieve the Python object related to a memory pointer to read its type and/or its content. Another issue is to retrieve the -location of the memory allocation: the C backtrace is usually useless +source of the memory allocation: the C backtrace is usually useless (same reasoning than macros using ``__FILE__`` and ``__LINE__``, see `Pass the C filename and line number`_), the Python filename and line number (or even the Python traceback) is more useful. This alternative was rejected because classic tools are unable to introspect Python internals to collect such information. Being able to -setup a hook on allocators called with the GIL held allow to collect a +setup a hook on allocators called with the GIL held allows to collect a lot of useful data from Python internals. @@ -606,7 +604,7 @@ On Windows, this function can be implemented using ``_msize()`` and ``VirtualQuery()``. -The function can be used to implement an hook tracking the memory usage. +The function can be used to implement a hook tracking the memory usage. The ``free()`` method of an allocator only gets the address of a memory block, whereas the size of the memory block is required to update the memory usage. @@ -614,9 +612,9 @@ The additional ``msize()`` function was rejected because only few platforms implement it. For example, Linux with the GNU libc does not provide a function to get the size of a memory block. ``msize()`` is not -currently used in the Python source code. The function is only used to -track the memory usage, and makes the API more complex. A debug hook can -implement the function internally, there is no need to add it to +currently used in the Python source code. The function would only be +used to track memory use, and make the API more complex. A debug hook +can implement the function internally, there is no need to add it to ``PyMemAllocator`` and ``PyObjectArenaAllocator`` structures. @@ -733,9 +731,9 @@ `_: efficient way to allocate groups of equal-sized chunks of memory -This PEP permits to choose exactly which memory allocator is used for your -application depending on its usage of the memory (number of allocation, size of -allocations, lifetime of objects, etc.). +This PEP allows to choose exactly which memory allocator is used for your +application depending on its usage of the memory (number of allocations, +size of allocations, lifetime of objects, etc.). Links -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Jul 6 22:58:08 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 6 Jul 2013 22:58:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Mark_accepted?= Message-ID: <3bnlcw22XvzSL9@mail.python.org> http://hg.python.org/peps/rev/7558862588d6 changeset: 4981:7558862588d6 user: Antoine Pitrou date: Sat Jul 06 22:56:39 2013 +0200 summary: Mark accepted files: pep-0445.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0445.txt b/pep-0445.txt --- a/pep-0445.txt +++ b/pep-0445.txt @@ -3,11 +3,12 @@ Version: $Revision$ Last-Modified: $Date$ Author: Victor Stinner -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 15-june-2013 Python-Version: 3.4 +Resolution: http://mail.python.org/pipermail/python-dev/2013-July/127222.html Abstract ======== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Jul 6 22:58:09 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 6 Jul 2013 22:58:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_=2E=2E=2E_and_mark_myself_as_?= =?utf-8?q?delegate?= Message-ID: <3bnlcx3x8XzSHQ@mail.python.org> http://hg.python.org/peps/rev/677b773f44f3 changeset: 4982:677b773f44f3 user: Antoine Pitrou date: Sat Jul 06 22:57:08 2013 +0200 summary: ... and mark myself as delegate files: pep-0445.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/pep-0445.txt b/pep-0445.txt --- a/pep-0445.txt +++ b/pep-0445.txt @@ -3,6 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Victor Stinner +BDFL-Delegate: Antoine Pitrou Status: Accepted Type: Standards Track Content-Type: text/x-rst -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 7 00:02:47 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 7 Jul 2013 00:02:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Refactor_deque=5Ftraverse?= =?utf-8?b?KCku?= Message-ID: <3bnn3W6RSQzSbH@mail.python.org> http://hg.python.org/cpython/rev/3555cc0ca35b changeset: 84466:3555cc0ca35b user: Raymond Hettinger date: Sat Jul 06 11:58:09 2013 -1000 summary: Refactor deque_traverse(). Hoist conditional expression out of the loop. Use rightblock as the guard instead of checking for NULL. files: Modules/_collectionsmodule.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -805,17 +805,17 @@ Py_ssize_t index; Py_ssize_t indexlo = deque->leftindex; - for (b = deque->leftblock; b != NULL; b = b->rightlink) { - const Py_ssize_t indexhi = b == deque->rightblock ? - deque->rightindex : - BLOCKLEN - 1; - - for (index = indexlo; index <= indexhi; ++index) { + for (b = deque->leftblock; b != deque->rightblock; b = b->rightlink) { + for (index = indexlo; index < BLOCKLEN ; index++) { item = b->data[index]; Py_VISIT(item); } indexlo = 0; } + for (index = indexlo; index <= deque->rightindex; index++) { + item = b->data[index]; + Py_VISIT(item); + } return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 00:05:13 2013 From: python-checkins at python.org (brett.cannon) Date: Sun, 7 Jul 2013 00:05:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzUx?= =?utf-8?q?=3A_Fix_various_issues_with?= Message-ID: <3bnn6K499KzSyb@mail.python.org> http://hg.python.org/cpython/rev/b8028f74bac4 changeset: 84467:b8028f74bac4 branch: 3.3 parent: 84462:c8fd1351c840 user: Brett Cannon date: Sat Jul 06 17:56:43 2013 -0400 summary: Issue #18351: Fix various issues with importlib._bootstrap._get_sourcefile(). Thanks to its only use by the C API, it was never properly tested until now. Thanks to Neal Norwitz for discovering the bug and Madison May for the patch. files: Lib/importlib/_bootstrap.py | 10 +- Lib/test/test_import.py | 38 +- Misc/ACKS | 1 + Misc/NEWS | 6 + Python/importlib.h | 6826 +++++++++++----------- 5 files changed, 3460 insertions(+), 3421 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -471,16 +471,14 @@ """ if len(bytecode_path) == 0: return None - rest, _, extension = bytecode_path.rparition('.') - if not rest or extension.lower()[-3:-1] != '.py': + rest, _, extension = bytecode_path.rpartition('.') + if not rest or extension.lower()[-3:-1] != 'py': return bytecode_path - try: source_path = source_from_cache(bytecode_path) except (NotImplementedError, ValueError): - source_path = bytcode_path[-1:] - - return source_path if _path_isfile(source_stats) else bytecode_path + source_path = bytecode_path[:-1] + return source_path if _path_isfile(source_path) else bytecode_path def _verbose_message(message, *args, verbosity=1): diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -1,5 +1,6 @@ # We import importlib *ASAP* in order to test #15386 import importlib +from importlib._bootstrap import _get_sourcefile import builtins import imp from test.test_importlib.import_ import util as importlib_util @@ -11,6 +12,7 @@ import stat import sys import unittest +import unittest.mock as mock import textwrap import errno import shutil @@ -864,6 +866,40 @@ self.assertIs(imp.new_module, mod.new_module) + at cpython_only +class GetSourcefileTests(unittest.TestCase): + + """Test importlib._bootstrap._get_sourcefile() as used by the C API. + + Because of the peculiarities of the need of this function, the tests are + knowingly whitebox tests. + + """ + + def test_get_sourcefile(self): + # Given a valid bytecode path, return the path to the corresponding + # source file if it exists. + with mock.patch('importlib._bootstrap._path_isfile') as _path_isfile: + _path_isfile.return_value = True; + path = TESTFN + '.pyc' + expect = TESTFN + '.py' + self.assertEqual(_get_sourcefile(path), expect) + + def test_get_sourcefile_no_source(self): + # Given a valid bytecode path without a corresponding source path, + # return the original bytecode path. + with mock.patch('importlib._bootstrap._path_isfile') as _path_isfile: + _path_isfile.return_value = False; + path = TESTFN + '.pyc' + self.assertEqual(_get_sourcefile(path), path) + + def test_get_sourcefile_bad_ext(self): + # Given a path with an invalid bytecode extension, return the + # bytecode path passed as the argument. + path = TESTFN + '.bad_ext' + self.assertEqual(_get_sourcefile(path), path) + + class ImportTracebackTests(unittest.TestCase): def setUp(self): @@ -1028,7 +1064,7 @@ run_unittest(ImportTests, PycacheTests, FilePermissionTests, PycRewritingTests, PathsTests, RelativeImportTests, OverridingImportBuiltinTests, - ImportlibBootstrapTests, + ImportlibBootstrapTests, GetSourcefileTests, TestSymbolicallyLinkedPackage, ImportTracebackTests) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -788,6 +788,7 @@ Graham Matthews Dieter Maurer Daniel May +Madison May Arnaud Mazin Rebecca McCreary Kirk McDonald diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -130,6 +130,12 @@ - Issue #18113: Fixed a refcount leak in the curses.panel module's set_userptr() method. Reported by Atsuo Ishimoto. +C API +----- + +- Issue #18351: Fix various issues with a helper function in importlib used + by PyImport_ExecCodeModuleWithPathnames() (and thus by extension PyImport_ExecCodeModule() and PyImport_ExecCodeModuleEx()). + IDLE ---- 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 Sun Jul 7 00:05:15 2013 From: python-checkins at python.org (brett.cannon) Date: Sun, 7 Jul 2013 00:05:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_for_issue_=2318351=2E?= Message-ID: <3bnn6M1B2fz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/e80634ad5a0e changeset: 84468:e80634ad5a0e parent: 84465:49a9c734304d parent: 84467:b8028f74bac4 user: Brett Cannon date: Sat Jul 06 18:04:41 2013 -0400 summary: merge for issue #18351. files: Lib/importlib/_bootstrap.py | 10 +- Lib/test/test_import.py | 36 + Misc/ACKS | 1 + Misc/NEWS | 3 + Python/importlib.h | 1600 +++++++++++----------- 5 files changed, 843 insertions(+), 807 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -443,16 +443,14 @@ """ if len(bytecode_path) == 0: return None - rest, _, extension = bytecode_path.rparition('.') - if not rest or extension.lower()[-3:-1] != '.py': + rest, _, extension = bytecode_path.rpartition('.') + if not rest or extension.lower()[-3:-1] != 'py': return bytecode_path - try: source_path = source_from_cache(bytecode_path) except (NotImplementedError, ValueError): - source_path = bytcode_path[-1:] - - return source_path if _path_isfile(source_stats) else bytecode_path + source_path = bytecode_path[:-1] + return source_path if _path_isfile(source_path) else bytecode_path def _calc_mode(path): diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -1,6 +1,7 @@ # We import importlib *ASAP* in order to test #15386 import importlib import importlib.util +from importlib._bootstrap import _get_sourcefile import builtins from test.test_importlib.import_ import util as importlib_util import marshal @@ -11,6 +12,7 @@ import stat import sys import unittest +import unittest.mock as mock import textwrap import errno import shutil @@ -851,6 +853,40 @@ self.assertIs(machinery.FileFinder, mod.FileFinder) + at cpython_only +class GetSourcefileTests(unittest.TestCase): + + """Test importlib._bootstrap._get_sourcefile() as used by the C API. + + Because of the peculiarities of the need of this function, the tests are + knowingly whitebox tests. + + """ + + def test_get_sourcefile(self): + # Given a valid bytecode path, return the path to the corresponding + # source file if it exists. + with mock.patch('importlib._bootstrap._path_isfile') as _path_isfile: + _path_isfile.return_value = True; + path = TESTFN + '.pyc' + expect = TESTFN + '.py' + self.assertEqual(_get_sourcefile(path), expect) + + def test_get_sourcefile_no_source(self): + # Given a valid bytecode path without a corresponding source path, + # return the original bytecode path. + with mock.patch('importlib._bootstrap._path_isfile') as _path_isfile: + _path_isfile.return_value = False; + path = TESTFN + '.pyc' + self.assertEqual(_get_sourcefile(path), path) + + def test_get_sourcefile_bad_ext(self): + # Given a path with an invalid bytecode extension, return the + # bytecode path passed as the argument. + path = TESTFN + '.bad_ext' + self.assertEqual(_get_sourcefile(path), path) + + class ImportTracebackTests(unittest.TestCase): def setUp(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -808,6 +808,7 @@ Graham Matthews Dieter Maurer Daniel May +Madison May Lucas Maystre Arnaud Mazin Rebecca McCreary diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -542,6 +542,9 @@ C-API ----- +- Issue #18351: Fix various issues in a function in importlib provided to help + PyImport_ExecCodeModuleWithPathnames() (and thus by extension PyImport_ExecCodeModule() and PyImport_ExecCodeModuleEx()). + - 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. 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 Sun Jul 7 00:05:16 2013 From: python-checkins at python.org (brett.cannon) Date: Sun, 7 Jul 2013 00:05:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bnn6N3Yxfz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/e8a1b4bcabcb changeset: 84469:e8a1b4bcabcb parent: 84468:e80634ad5a0e parent: 84466:3555cc0ca35b user: Brett Cannon date: Sat Jul 06 18:05:02 2013 -0400 summary: merge files: Modules/_collectionsmodule.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -805,17 +805,17 @@ Py_ssize_t index; Py_ssize_t indexlo = deque->leftindex; - for (b = deque->leftblock; b != NULL; b = b->rightlink) { - const Py_ssize_t indexhi = b == deque->rightblock ? - deque->rightindex : - BLOCKLEN - 1; - - for (index = indexlo; index <= indexhi; ++index) { + for (b = deque->leftblock; b != deque->rightblock; b = b->rightlink) { + for (index = indexlo; index < BLOCKLEN ; index++) { item = b->data[index]; Py_VISIT(item); } indexlo = 0; } + for (index = indexlo; index <= deque->rightindex; index++) { + item = b->data[index]; + Py_VISIT(item); + } return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 01:01:44 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 7 Jul 2013 01:01:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Apply_the_PyObject=5FVAR?= =?utf-8?q?=5FHEAD_and_Py=5FSIZE_macros?= Message-ID: <3bnpMX3lQjzSmK@mail.python.org> http://hg.python.org/cpython/rev/9166aa413d6f changeset: 84470:9166aa413d6f user: Raymond Hettinger date: Sat Jul 06 13:01:13 2013 -1000 summary: Apply the PyObject_VAR_HEAD and Py_SIZE macros to be consistent with practices in other modules. files: Modules/_collectionsmodule.c | 79 +++++++++++------------ 1 files changed, 39 insertions(+), 40 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -93,12 +93,11 @@ } typedef struct { - PyObject_HEAD + PyObject_VAR_HEAD block *leftblock; block *rightblock; Py_ssize_t leftindex; /* in range(BLOCKLEN) */ Py_ssize_t rightindex; /* in range(BLOCKLEN) */ - Py_ssize_t len; Py_ssize_t maxlen; long state; /* incremented whenever the indices move */ PyObject *weakreflist; /* List of weak references */ @@ -114,9 +113,9 @@ */ #define TRIM(d, popfunction) \ - if (d->maxlen != -1 && d->len > d->maxlen) { \ + if (d->maxlen != -1 && Py_SIZE(d) > d->maxlen) { \ PyObject *rv = popfunction(d, NULL); \ - assert(rv != NULL && d->len <= d->maxlen); \ + assert(rv != NULL && Py_SIZE(d) <= d->maxlen); \ Py_DECREF(rv); \ } @@ -144,7 +143,7 @@ deque->rightblock = b; deque->leftindex = CENTER + 1; deque->rightindex = CENTER; - deque->len = 0; + Py_SIZE(deque) = 0; deque->state = 0; deque->weakreflist = NULL; deque->maxlen = -1; @@ -158,17 +157,17 @@ PyObject *item; block *prevblock; - if (deque->len == 0) { + if (Py_SIZE(deque) == 0) { PyErr_SetString(PyExc_IndexError, "pop from an empty deque"); return NULL; } item = deque->rightblock->data[deque->rightindex]; deque->rightindex--; - deque->len--; + Py_SIZE(deque)--; deque->state++; if (deque->rightindex == -1) { - if (deque->len == 0) { + if (Py_SIZE(deque) == 0) { assert(deque->leftblock == deque->rightblock); assert(deque->leftindex == deque->rightindex+1); /* re-center instead of freeing a block */ @@ -194,18 +193,18 @@ PyObject *item; block *prevblock; - if (deque->len == 0) { + if (Py_SIZE(deque) == 0) { PyErr_SetString(PyExc_IndexError, "pop from an empty deque"); return NULL; } assert(deque->leftblock != NULL); item = deque->leftblock->data[deque->leftindex]; deque->leftindex++; - deque->len--; + Py_SIZE(deque)--; deque->state++; if (deque->leftindex == BLOCKLEN) { - if (deque->len == 0) { + if (Py_SIZE(deque) == 0) { assert(deque->leftblock == deque->rightblock); assert(deque->leftindex == deque->rightindex+1); /* re-center instead of freeing a block */ @@ -231,7 +230,7 @@ { deque->state++; if (deque->rightindex == BLOCKLEN-1) { - block *b = newblock(deque->rightblock, NULL, deque->len); + block *b = newblock(deque->rightblock, NULL, Py_SIZE(deque)); if (b == NULL) return NULL; assert(deque->rightblock->rightlink == NULL); @@ -240,7 +239,7 @@ deque->rightindex = -1; } Py_INCREF(item); - deque->len++; + Py_SIZE(deque)++; deque->rightindex++; deque->rightblock->data[deque->rightindex] = item; TRIM(deque, deque_popleft); @@ -254,7 +253,7 @@ { deque->state++; if (deque->leftindex == 0) { - block *b = newblock(NULL, deque->leftblock, deque->len); + block *b = newblock(NULL, deque->leftblock, Py_SIZE(deque)); if (b == NULL) return NULL; assert(deque->leftblock->leftlink == NULL); @@ -263,7 +262,7 @@ deque->leftindex = BLOCKLEN; } Py_INCREF(item); - deque->len++; + Py_SIZE(deque)++; deque->leftindex--; deque->leftblock->data[deque->leftindex] = item; TRIM(deque, deque_pop); @@ -316,7 +315,7 @@ deque->state++; if (deque->rightindex == BLOCKLEN-1) { block *b = newblock(deque->rightblock, NULL, - deque->len); + Py_SIZE(deque)); if (b == NULL) { Py_DECREF(item); Py_DECREF(it); @@ -327,7 +326,7 @@ deque->rightblock = b; deque->rightindex = -1; } - deque->len++; + Py_SIZE(deque)++; deque->rightindex++; deque->rightblock->data[deque->rightindex] = item; TRIM(deque, deque_popleft); @@ -368,7 +367,7 @@ deque->state++; if (deque->leftindex == 0) { block *b = newblock(NULL, deque->leftblock, - deque->len); + Py_SIZE(deque)); if (b == NULL) { Py_DECREF(item); Py_DECREF(it); @@ -379,7 +378,7 @@ deque->leftblock = b; deque->leftindex = BLOCKLEN; } - deque->len++; + Py_SIZE(deque)++; deque->leftindex--; deque->leftblock->data[deque->leftindex] = item; TRIM(deque, deque_pop); @@ -413,7 +412,7 @@ block *rightblock = deque->rightblock; Py_ssize_t leftindex = deque->leftindex; Py_ssize_t rightindex = deque->rightindex; - Py_ssize_t len=deque->len, halflen=len>>1; + Py_ssize_t len=Py_SIZE(deque), halflen=len>>1; int rv = 0; if (len <= 1) @@ -544,7 +543,7 @@ block *rightblock = deque->rightblock; Py_ssize_t leftindex = deque->leftindex; Py_ssize_t rightindex = deque->rightindex; - Py_ssize_t n = (deque->len)/2; + Py_ssize_t n = (Py_SIZE(deque))/2; Py_ssize_t i; PyObject *tmp; @@ -584,7 +583,7 @@ { block *leftblock = deque->leftblock; Py_ssize_t leftindex = deque->leftindex; - Py_ssize_t n = deque->len; + Py_ssize_t n = Py_SIZE(deque); Py_ssize_t i; Py_ssize_t count = 0; PyObject *item; @@ -622,19 +621,19 @@ static Py_ssize_t deque_len(dequeobject *deque) { - return deque->len; + return Py_SIZE(deque); } static PyObject * deque_remove(dequeobject *deque, PyObject *value) { - Py_ssize_t i, n=deque->len; + Py_ssize_t i, n=Py_SIZE(deque); for (i=0 ; ileftblock->data[deque->leftindex]; int cmp = PyObject_RichCompareBool(item, value, Py_EQ); - if (deque->len != n) { + if (Py_SIZE(deque) != n) { PyErr_SetString(PyExc_IndexError, "deque mutated during remove()."); return NULL; @@ -665,14 +664,14 @@ { PyObject *item; - while (deque->len) { + while (Py_SIZE(deque)) { item = deque_pop(deque, NULL); assert (item != NULL); Py_DECREF(item); } assert(deque->leftblock == deque->rightblock && deque->leftindex - 1 == deque->rightindex && - deque->len == 0); + Py_SIZE(deque) == 0); } static PyObject * @@ -682,7 +681,7 @@ PyObject *item; Py_ssize_t n, index=i; - if (i < 0 || i >= deque->len) { + if (i < 0 || i >= Py_SIZE(deque)) { PyErr_SetString(PyExc_IndexError, "deque index out of range"); return NULL; @@ -691,19 +690,19 @@ if (i == 0) { i = deque->leftindex; b = deque->leftblock; - } else if (i == deque->len - 1) { + } else if (i == Py_SIZE(deque) - 1) { i = deque->rightindex; b = deque->rightblock; } else { i += deque->leftindex; n = i / BLOCKLEN; i %= BLOCKLEN; - if (index < (deque->len >> 1)) { + if (index < (Py_SIZE(deque) >> 1)) { b = deque->leftblock; while (n--) b = b->rightlink; } else { - n = (deque->leftindex + deque->len - 1) / BLOCKLEN - n; + n = (deque->leftindex + Py_SIZE(deque) - 1) / BLOCKLEN - n; b = deque->rightblock; while (n--) b = b->leftlink; @@ -726,7 +725,7 @@ { PyObject *item; - assert (i >= 0 && i < deque->len); + assert (i >= 0 && i < Py_SIZE(deque)); if (_deque_rotate(deque, -i) == -1) return -1; @@ -742,7 +741,7 @@ { PyObject *old_value; block *b; - Py_ssize_t n, len=deque->len, halflen=(len+1)>>1, index=i; + Py_ssize_t n, len=Py_SIZE(deque), halflen=(len+1)>>1, index=i; if (i < 0 || i >= len) { PyErr_SetString(PyExc_IndexError, @@ -905,8 +904,8 @@ } /* Shortcuts */ - vs = ((dequeobject *)v)->len; - ws = ((dequeobject *)w)->len; + vs = Py_SIZE((dequeobject *)v); + ws = Py_SIZE((dequeobject *)w); if (op == Py_EQ) { if (v == w) Py_RETURN_TRUE; @@ -1007,8 +1006,8 @@ Py_ssize_t blocks; res = sizeof(dequeobject); - blocks = (deque->leftindex + deque->len + BLOCKLEN - 1) / BLOCKLEN; - assert(deque->leftindex + deque->len - 1 == + blocks = (deque->leftindex + Py_SIZE(deque) + BLOCKLEN - 1) / BLOCKLEN; + assert(deque->leftindex + Py_SIZE(deque) - 1 == (blocks - 1) * BLOCKLEN + deque->rightindex); res += blocks * sizeof(block); return PyLong_FromSsize_t(res); @@ -1161,7 +1160,7 @@ Py_INCREF(deque); it->deque = deque; it->state = deque->state; - it->counter = deque->len; + it->counter = Py_SIZE(deque); PyObject_GC_Track(it); return (PyObject *)it; } @@ -1248,7 +1247,7 @@ static PyObject * dequeiter_reduce(dequeiterobject *it) { - return Py_BuildValue("O(On)", Py_TYPE(it), it->deque, it->deque->len - it->counter); + return Py_BuildValue("O(On)", Py_TYPE(it), it->deque, Py_SIZE(it->deque) - it->counter); } static PyMethodDef dequeiter_methods[] = { @@ -1317,7 +1316,7 @@ Py_INCREF(deque); it->deque = deque; it->state = deque->state; - it->counter = deque->len; + it->counter = Py_SIZE(deque); PyObject_GC_Track(it); return (PyObject *)it; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 02:25:37 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 02:25:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=233329=3A_Implement?= =?utf-8?q?_the_PEP_445?= Message-ID: <3bnrDK06HkzRZn@mail.python.org> http://hg.python.org/cpython/rev/ca78c974e938 changeset: 84471:ca78c974e938 user: Victor Stinner date: Sun Jul 07 02:05:46 2013 +0200 summary: Issue #3329: Implement the PEP 445 Add new enum: * PyMemAllocatorDomain Add new structures: * PyMemAllocator * PyObjectArenaAllocator Add new functions: * PyMem_RawMalloc(), PyMem_RawRealloc(), PyMem_RawFree() * PyMem_GetAllocator(), PyMem_SetAllocator() * PyObject_GetArenaAllocator(), PyObject_SetArenaAllocator() * PyMem_SetupDebugHooks() Changes: * PyMem_Malloc()/PyObject_Realloc() now always call malloc()/realloc(), instead of calling PyObject_Malloc()/PyObject_Realloc() in debug mode. * PyObject_Malloc()/PyObject_Realloc() now falls back to PyMem_Malloc()/PyMem_Realloc() for allocations larger than 512 bytes. * Redesign debug checks on memory block allocators as hooks, instead of using C macros files: Doc/c-api/memory.rst | 171 ++++++++- Doc/whatsnew/3.4.rst | 18 +- Include/objimpl.h | 60 +- Include/pymem.h | 94 +++- Misc/NEWS | 3 + Modules/_testcapimodule.c | 163 ++++++++ Objects/object.c | 20 - Objects/obmalloc.c | 504 ++++++++++++++++++------- 8 files changed, 796 insertions(+), 237 deletions(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -84,6 +84,48 @@ for the I/O buffer escapes completely the Python memory manager. +Raw Memory Interface +==================== + +The following function sets are wrappers to the system allocator. These +functions are thread-safe, the :term:`GIL ` does not +need to be held. + +The default raw memory block allocator uses the following functions: +:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when +requesting zero bytes. + +.. versionadded:: 3.4 + +.. c:function:: void* PyMem_RawMalloc(size_t n) + + Allocates *n* bytes and returns a pointer of type :c:type:`void\*` to the + allocated memory, or *NULL* if the request fails. Requesting zero bytes + returns a distinct non-*NULL* pointer if possible, as if + ``PyMem_RawMalloc(1)`` had been called instead. The memory will not have + been initialized in any way. + + +.. c:function:: void* PyMem_RawRealloc(void *p, size_t n) + + Resizes the memory block pointed to by *p* to *n* bytes. The contents will + be unchanged to the minimum of the old and the new sizes. If *p* is *NULL*, + the call is equivalent to ``PyMem_RawMalloc(n)``; else if *n* is equal to + zero, the memory block is resized but is not freed, and the returned pointer + is non-*NULL*. Unless *p* is *NULL*, it must have been returned by a + previous call to :c:func:`PyMem_RawMalloc` or :c:func:`PyMem_RawRealloc`. If + the request fails, :c:func:`PyMem_RawRealloc` returns *NULL* and *p* remains + a valid pointer to the previous memory area. + + +.. c:function:: void PyMem_RawFree(void *p) + + Frees the memory block pointed to by *p*, which must have been returned by a + previous call to :c:func:`PyMem_RawMalloc` or :c:func:`PyMem_RawRealloc`. + Otherwise, or if ``PyMem_Free(p)`` has been called before, undefined + behavior occurs. If *p* is *NULL*, no operation is performed. + + .. _memoryinterface: Memory Interface @@ -91,8 +133,16 @@ The following function sets, modeled after the ANSI C standard, but specifying behavior when requesting zero bytes, are available for allocating and releasing -memory from the Python heap: +memory from the Python heap. +The default memory block allocator uses the following functions: +:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when +requesting zero bytes. + +.. warning:: + + The :term:`GIL ` must be held when using these + functions. .. c:function:: void* PyMem_Malloc(size_t n) @@ -155,6 +205,125 @@ :c:func:`PyMem_NEW`, :c:func:`PyMem_RESIZE`, :c:func:`PyMem_DEL`. +Customize Memory Allocators +=========================== + +.. versionadded:: 3.4 + +.. c:type:: PyMemAllocator + + Structure used to describe a memory block allocator. The structure has + four fields: + + +----------------------------------------------------------+---------------------------------------+ + | Field | Meaning | + +==========================================================+=======================================+ + | ``void *ctx`` | user context passed as first argument | + +----------------------------------------------------------+---------------------------------------+ + | ``void* malloc(void *ctx, size_t size)`` | allocate a memory block | + +----------------------------------------------------------+---------------------------------------+ + | ``void* realloc(void *ctx, void *ptr, size_t new_size)`` | allocate or resize a memory block | + +----------------------------------------------------------+---------------------------------------+ + | ``void free(void *ctx, void *ptr)`` | free a memory block | + +----------------------------------------------------------+---------------------------------------+ + +.. c:type:: PyMemAllocatorDomain + + Enum used to identify an allocator domain. Domains: + + * :c:data:`PYMEM_DOMAIN_RAW`: functions :c:func:`PyMem_RawMalloc`, + :c:func:`PyMem_RawRealloc` and :c:func:`PyMem_RawFree` + * :c:data:`PYMEM_DOMAIN_MEM`: functions :c:func:`PyMem_Malloc`, + :c:func:`PyMem_Realloc` and :c:func:`PyMem_Free` + * :c:data:`PYMEM_DOMAIN_OBJ`: functions :c:func:`PyObject_Malloc`, + :c:func:`PyObject_Realloc` and :c:func:`PyObject_Free` + + +.. c:function:: void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator) + + Get the memory block allocator of the specified domain. + + +.. c:function:: void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator) + + Set the memory block allocator of the specified domain. + + The new allocator must return a distinct non-NULL pointer when requesting + zero bytes. + + For the :c:data:`PYMEM_DOMAIN_RAW` domain, the allocator must be + thread-safe: the :term:`GIL ` is not held when the + allocator is called. + + If the new allocator is not a hook (does not call the previous allocator), + the :c:func:`PyMem_SetupDebugHooks` function must be called to reinstall the + debug hooks on top on the new allocator. + + +.. c:function:: void PyMem_SetupDebugHooks(void) + + Setup hooks to detect bugs in the following Python memory allocator + functions: + + - :c:func:`PyMem_RawMalloc`, :c:func:`PyMem_RawRealloc`, + :c:func:`PyMem_RawFree` + - :c:func:`PyMem_Malloc`, :c:func:`PyMem_Realloc`, :c:func:`PyMem_Free` + - :c:func:`PyObject_Malloc`, :c:func:`PyObject_Realloc`, + :c:func:`PyObject_Free` + + Newly allocated memory is filled with the byte ``0xCB``, freed memory is + filled with the byte ``0xDB``. Additionnal checks: + + - detect API violations, ex: :c:func:`PyObject_Free` called on a buffer + allocated by :c:func:`PyMem_Malloc` + - detect write before the start of the buffer (buffer underflow) + - detect write after the end of the buffer (buffer overflow) + + The function does nothing if Python is not compiled is debug mode. + + +Customize PyObject Arena Allocator +================================== + +Python has a *pymalloc* allocator for allocations smaller than 512 bytes. This +allocator is optimized for small objects with a short lifetime. It uses memory +mappings called "arenas" with a fixed size of 256 KB. It falls back to +:c:func:`PyMem_Malloc` and :c:func:`PyMem_Realloc` for allocations larger than +512 bytes. *pymalloc* is the default allocator used by +:c:func:`PyObject_Malloc`. + +The default arena allocator uses the following functions: + +* :c:func:`VirtualAlloc` and :c:func:`VirtualFree` on Windows, +* :c:func:`mmap` and :c:func:`munmap` if available, +* :c:func:`malloc` and :c:func:`free` otherwise. + +.. versionadded:: 3.4 + +.. c:type:: PyObjectArenaAllocator + + Structure used to describe an arena allocator. The structure has + three fields: + + +--------------------------------------------------+---------------------------------------+ + | Field | Meaning | + +==================================================+=======================================+ + | ``void *ctx`` | user context passed as first argument | + +--------------------------------------------------+---------------------------------------+ + | ``void* alloc(void *ctx, size_t size)`` | allocate an arena of size bytes | + +--------------------------------------------------+---------------------------------------+ + | ``void free(void *ctx, size_t size, void *ptr)`` | free an arena | + +--------------------------------------------------+---------------------------------------+ + +.. c:function:: PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator) + + Get the arena allocator. + +.. c:function:: PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator) + + Set the arena allocator. + + .. _memoryexamples: Examples 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 @@ -112,21 +112,11 @@ Please read on for a comprehensive list of user-facing changes. -.. PEP-sized items next. +PEP 445: Add new APIs to customize Python memory allocators +=========================================================== -.. _pep-4XX: - -.. PEP 4XX: Example PEP -.. ==================== - - -.. (Implemented by Foo Bar.) - -.. .. seealso:: - - :pep:`4XX` - Example PEP - PEP written by Example Author - +The :pep:`445` adds new Application Programming Interfaces (API) to customize +Python memory allocators. diff --git a/Include/objimpl.h b/Include/objimpl.h --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -94,9 +94,9 @@ the object gets initialized via PyObject_{Init, InitVar} after obtaining the raw memory. */ -PyAPI_FUNC(void *) PyObject_Malloc(size_t); -PyAPI_FUNC(void *) PyObject_Realloc(void *, size_t); -PyAPI_FUNC(void) PyObject_Free(void *); +PyAPI_FUNC(void *) PyObject_Malloc(size_t size); +PyAPI_FUNC(void *) PyObject_Realloc(void *ptr, size_t new_size); +PyAPI_FUNC(void) PyObject_Free(void *ptr); /* This function returns the number of allocated memory blocks, regardless of size */ PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void); @@ -106,41 +106,15 @@ #ifndef Py_LIMITED_API PyAPI_FUNC(void) _PyObject_DebugMallocStats(FILE *out); #endif /* #ifndef Py_LIMITED_API */ -#ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */ -PyAPI_FUNC(void *) _PyObject_DebugMalloc(size_t nbytes); -PyAPI_FUNC(void *) _PyObject_DebugRealloc(void *p, size_t nbytes); -PyAPI_FUNC(void) _PyObject_DebugFree(void *p); -PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p); -PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p); -PyAPI_FUNC(void *) _PyObject_DebugMallocApi(char api, size_t nbytes); -PyAPI_FUNC(void *) _PyObject_DebugReallocApi(char api, void *p, size_t nbytes); -PyAPI_FUNC(void) _PyObject_DebugFreeApi(char api, void *p); -PyAPI_FUNC(void) _PyObject_DebugCheckAddressApi(char api, const void *p); -PyAPI_FUNC(void *) _PyMem_DebugMalloc(size_t nbytes); -PyAPI_FUNC(void *) _PyMem_DebugRealloc(void *p, size_t nbytes); -PyAPI_FUNC(void) _PyMem_DebugFree(void *p); -#define PyObject_MALLOC _PyObject_DebugMalloc -#define PyObject_Malloc _PyObject_DebugMalloc -#define PyObject_REALLOC _PyObject_DebugRealloc -#define PyObject_Realloc _PyObject_DebugRealloc -#define PyObject_FREE _PyObject_DebugFree -#define PyObject_Free _PyObject_DebugFree +#endif -#else /* WITH_PYMALLOC && ! PYMALLOC_DEBUG */ +/* Macros */ #define PyObject_MALLOC PyObject_Malloc #define PyObject_REALLOC PyObject_Realloc #define PyObject_FREE PyObject_Free -#endif +#define PyObject_Del PyObject_Free +#define PyObject_DEL PyObject_Free -#else /* ! WITH_PYMALLOC */ -#define PyObject_MALLOC PyMem_MALLOC -#define PyObject_REALLOC PyMem_REALLOC -#define PyObject_FREE PyMem_FREE - -#endif /* WITH_PYMALLOC */ - -#define PyObject_Del PyObject_Free -#define PyObject_DEL PyObject_FREE /* * Generic object allocator interface @@ -224,6 +198,26 @@ constructor you would start directly with PyObject_Init/InitVar */ +#ifndef Py_LIMITED_API +typedef struct { + /* user context passed as the first argument to the 2 functions */ + void *ctx; + + /* allocate an arena of size bytes */ + void* (*alloc) (void *ctx, size_t size); + + /* free an arena */ + void (*free) (void *ctx, void *ptr, size_t size); +} PyObjectArenaAllocator; + +/* Get the arena allocator. */ +PyAPI_FUNC(void) PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator); + +/* Set the arena allocator. */ +PyAPI_FUNC(void) PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator); +#endif + + /* * Garbage Collection Support * ========================== diff --git a/Include/pymem.h b/Include/pymem.h --- a/Include/pymem.h +++ b/Include/pymem.h @@ -11,6 +11,11 @@ extern "C" { #endif +PyAPI_FUNC(void *) PyMem_RawMalloc(size_t size); +PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size); +PyAPI_FUNC(void) PyMem_RawFree(void *ptr); + + /* BEWARE: Each interface exports both functions and macros. Extension modules should @@ -49,21 +54,11 @@ performed on failure (no exception is set, no warning is printed, etc). */ -PyAPI_FUNC(void *) PyMem_Malloc(size_t); -PyAPI_FUNC(void *) PyMem_Realloc(void *, size_t); -PyAPI_FUNC(void) PyMem_Free(void *); - -/* Starting from Python 1.6, the wrappers Py_{Malloc,Realloc,Free} are - no longer supported. They used to call PyErr_NoMemory() on failure. */ +PyAPI_FUNC(void *) PyMem_Malloc(size_t size); +PyAPI_FUNC(void *) PyMem_Realloc(void *ptr, size_t new_size); +PyAPI_FUNC(void) PyMem_Free(void *ptr); /* Macros. */ -#ifdef PYMALLOC_DEBUG -/* Redirect all memory operations to Python's debugging allocator. */ -#define PyMem_MALLOC _PyMem_DebugMalloc -#define PyMem_REALLOC _PyMem_DebugRealloc -#define PyMem_FREE _PyMem_DebugFree - -#else /* ! PYMALLOC_DEBUG */ /* PyMem_MALLOC(0) means malloc(1). Some systems would return NULL for malloc(0), which would be treated as an error. Some platforms @@ -71,13 +66,9 @@ pymalloc. To solve these problems, allocate an extra byte. */ /* Returns NULL to indicate error if a negative size or size larger than Py_ssize_t can represent is supplied. Helps prevents security holes. */ -#define PyMem_MALLOC(n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \ - : malloc((n) ? (n) : 1)) -#define PyMem_REALLOC(p, n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \ - : realloc((p), (n) ? (n) : 1)) -#define PyMem_FREE free - -#endif /* PYMALLOC_DEBUG */ +#define PyMem_MALLOC(n) PyMem_Malloc(n) +#define PyMem_REALLOC(p, n) PyMem_Realloc(p, n) +#define PyMem_FREE(p) PyMem_Free(p) /* * Type-oriented memory interface @@ -115,6 +106,69 @@ #define PyMem_Del PyMem_Free #define PyMem_DEL PyMem_FREE +#ifndef Py_LIMITED_API +typedef enum { + /* PyMem_RawMalloc(), PyMem_RawRealloc() and PyMem_RawFree() */ + PYMEM_DOMAIN_RAW, + + /* PyMem_Malloc(), PyMem_Realloc() and PyMem_Free() */ + PYMEM_DOMAIN_MEM, + + /* PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() */ + PYMEM_DOMAIN_OBJ +} PyMemAllocatorDomain; + +typedef struct { + /* user context passed as the first argument to the 3 functions */ + void *ctx; + + /* allocate a memory block */ + void* (*malloc) (void *ctx, size_t size); + + /* allocate or resize a memory block */ + void* (*realloc) (void *ctx, void *ptr, size_t new_size); + + /* release a memory block */ + void (*free) (void *ctx, void *ptr); +} PyMemAllocator; + +/* Get the memory block allocator of the specified domain. */ +PyAPI_FUNC(void) PyMem_GetAllocator(PyMemAllocatorDomain domain, + PyMemAllocator *allocator); + +/* Set the memory block allocator of the specified domain. + + The new allocator must return a distinct non-NULL pointer when requesting + zero bytes. + + For the PYMEM_DOMAIN_RAW domain, the allocator must be thread-safe: the GIL + is not held when the allocator is called. + + If the new allocator is not a hook (don't call the previous allocator), the + PyMem_SetupDebugHooks() function must be called to reinstall the debug hooks + on top on the new allocator. */ +PyAPI_FUNC(void) PyMem_SetAllocator(PyMemAllocatorDomain domain, + PyMemAllocator *allocator); + +/* Setup hooks to detect bugs in the following Python memory allocator + functions: + + - PyMem_RawMalloc(), PyMem_RawRealloc(), PyMem_RawFree() + - PyMem_Malloc(), PyMem_Realloc(), PyMem_Free() + - PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() + + Newly allocated memory is filled with the byte 0xCB, freed memory is filled + with the byte 0xDB. Additionnal checks: + + - detect API violations, ex: PyObject_Free() called on a buffer allocated + by PyMem_Malloc() + - detect write before the start of the buffer (buffer underflow) + - detect write after the end of the buffer (buffer overflow) + + The function does nothing if Python is not compiled is debug mode. */ +PyAPI_FUNC(void) PyMem_SetupDebugHooks(void); +#endif + #ifdef __cplusplus } #endif diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #3329: Implement the PEP 445: Add new APIs to customize Python memory + allocators. + - Issue #18328: Reorder ops in PyThreadState_Delete*() functions. Now the tstate is first removed from TLS and then deallocated. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2511,6 +2511,161 @@ Py_RETURN_NONE; } +static PyObject * +test_pymem_alloc0(PyObject *self) +{ + void *ptr; + + ptr = PyMem_Malloc(0); + if (ptr == NULL) { + PyErr_SetString(PyExc_RuntimeError, "PyMem_Malloc(0) returns NULL"); + return NULL; + } + PyMem_Free(ptr); + + ptr = PyObject_Malloc(0); + if (ptr == NULL) { + PyErr_SetString(PyExc_RuntimeError, "PyObject_Malloc(0) returns NULL"); + return NULL; + } + PyObject_Free(ptr); + + Py_RETURN_NONE; +} + +typedef struct { + PyMemAllocator alloc; + + size_t malloc_size; + void *realloc_ptr; + size_t realloc_new_size; + void *free_ptr; +} alloc_hook_t; + +static void* hook_malloc (void* ctx, size_t size) +{ + alloc_hook_t *hook = (alloc_hook_t *)ctx; + hook->malloc_size = size; + return hook->alloc.malloc(hook->alloc.ctx, size); +} + +static void* hook_realloc (void* ctx, void* ptr, size_t new_size) +{ + alloc_hook_t *hook = (alloc_hook_t *)ctx; + hook->realloc_ptr = ptr; + hook->realloc_new_size = new_size; + return hook->alloc.realloc(hook->alloc.ctx, ptr, new_size); +} + +static void hook_free (void *ctx, void *ptr) +{ + alloc_hook_t *hook = (alloc_hook_t *)ctx; + hook->free_ptr = ptr; + hook->alloc.free(hook->alloc.ctx, ptr); +} + +static PyObject * +test_setallocators(PyMemAllocatorDomain domain) +{ + PyObject *res = NULL; + const char *error_msg; + alloc_hook_t hook; + PyMemAllocator alloc; + size_t size, size2; + void *ptr, *ptr2; + + hook.malloc_size = 0; + hook.realloc_ptr = NULL; + hook.realloc_new_size = 0; + hook.free_ptr = NULL; + + alloc.ctx = &hook; + alloc.malloc = &hook_malloc; + alloc.realloc = &hook_realloc; + alloc.free = &hook_free; + PyMem_GetAllocator(domain, &hook.alloc); + PyMem_SetAllocator(domain, &alloc); + + size = 42; + switch(domain) + { + case PYMEM_DOMAIN_RAW: ptr = PyMem_RawMalloc(size); break; + case PYMEM_DOMAIN_MEM: ptr = PyMem_Malloc(size); break; + case PYMEM_DOMAIN_OBJ: ptr = PyObject_Malloc(size); break; + default: ptr = NULL; break; + } + + if (ptr == NULL) { + error_msg = "malloc failed"; + goto fail; + } + + if (hook.malloc_size != size) { + error_msg = "malloc invalid size"; + goto fail; + } + + size2 = 200; + switch(domain) + { + case PYMEM_DOMAIN_RAW: ptr2 = PyMem_RawRealloc(ptr, size2); break; + case PYMEM_DOMAIN_MEM: ptr2 = PyMem_Realloc(ptr, size2); break; + case PYMEM_DOMAIN_OBJ: ptr2 = PyObject_Realloc(ptr, size2); break; + } + + if (ptr2 == NULL) { + error_msg = "realloc failed"; + goto fail; + } + + if (hook.realloc_ptr != ptr + || hook.realloc_new_size != size2) { + error_msg = "realloc invalid parameters"; + goto fail; + } + + switch(domain) + { + case PYMEM_DOMAIN_RAW: PyMem_RawFree(ptr2); break; + case PYMEM_DOMAIN_MEM: PyMem_Free(ptr2); break; + case PYMEM_DOMAIN_OBJ: PyObject_Free(ptr2); break; + } + + if (hook.free_ptr != ptr2) { + error_msg = "free invalid pointer"; + goto fail; + } + + Py_INCREF(Py_None); + res = Py_None; + goto finally; + +fail: + PyErr_SetString(PyExc_RuntimeError, error_msg); + +finally: + PyMem_SetAllocator(domain, &hook.alloc); + return res; +} + +static PyObject * +test_pymem_setrawallocators(PyObject *self) +{ + return test_setallocators(PYMEM_DOMAIN_RAW); +} + +static PyObject * +test_pymem_setallocators(PyObject *self) +{ + return test_setallocators(PYMEM_DOMAIN_MEM); +} + +static PyObject * +test_pyobject_setallocators(PyObject *self) +{ + return test_setallocators(PYMEM_DOMAIN_OBJ); +} + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS}, @@ -2611,6 +2766,14 @@ {"pytime_object_to_time_t", test_pytime_object_to_time_t, METH_VARARGS}, {"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS}, {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, + {"test_pymem", + (PyCFunction)test_pymem_alloc0, METH_NOARGS}, + {"test_pymem_alloc0", + (PyCFunction)test_pymem_setrawallocators, METH_NOARGS}, + {"test_pymem_setallocators", + (PyCFunction)test_pymem_setallocators, METH_NOARGS}, + {"test_pyobject_setallocators", + (PyCFunction)test_pyobject_setallocators, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -1859,26 +1859,6 @@ Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size; -/* Python's malloc wrappers (see pymem.h) */ - -void * -PyMem_Malloc(size_t nbytes) -{ - return PyMem_MALLOC(nbytes); -} - -void * -PyMem_Realloc(void *p, size_t nbytes) -{ - return PyMem_REALLOC(p, nbytes); -} - -void -PyMem_Free(void *p) -{ - PyMem_FREE(p); -} - void _PyObject_DebugTypeStats(FILE *out) { diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -1,18 +1,326 @@ #include "Python.h" +/* Python's malloc wrappers (see pymem.h) */ + +#ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */ +/* Forward declaration */ +static void* _PyMem_DebugMalloc(void *ctx, size_t size); +static void _PyMem_DebugFree(void *ctx, void *p); +static void* _PyMem_DebugRealloc(void *ctx, void *ptr, size_t size); + +static void _PyObject_DebugDumpAddress(const void *p); +static void _PyMem_DebugCheckAddress(char api_id, const void *p); +#endif + #ifdef WITH_PYMALLOC -#ifdef HAVE_MMAP - #include - #ifdef MAP_ANONYMOUS - #define ARENAS_USE_MMAP - #endif +#ifdef MS_WINDOWS +# include +#elif defined(HAVE_MMAP) +# include +# ifdef MAP_ANONYMOUS +# define ARENAS_USE_MMAP +# endif #endif +/* Forward declaration */ +static void* _PyObject_Malloc(void *ctx, size_t size); +static void _PyObject_Free(void *ctx, void *p); +static void* _PyObject_Realloc(void *ctx, void *ptr, size_t size); +#endif + + +static void * +_PyMem_RawMalloc(void *ctx, size_t size) +{ + /* PyMem_Malloc(0) means malloc(1). Some systems would return NULL + for malloc(0), which would be treated as an error. Some platforms would + return a pointer with no memory behind it, which would break pymalloc. + To solve these problems, allocate an extra byte. */ + if (size == 0) + size = 1; + return malloc(size); +} + +static void * +_PyMem_RawRealloc(void *ctx, void *ptr, size_t size) +{ + if (size == 0) + size = 1; + return realloc(ptr, size); +} + +static void +_PyMem_RawFree(void *ctx, void *ptr) +{ + free(ptr); +} + + #ifdef MS_WINDOWS -#include +static void * +_PyObject_ArenaVirtualAlloc(void *ctx, size_t size) +{ + return VirtualAlloc(NULL, size, + MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +} + +static void +_PyObject_ArenaVirtualFree(void *ctx, void *ptr, size_t size) +{ + VirtualFree(ptr, size, MEM_RELEASE); +} + +#elif defined(ARENAS_USE_MMAP) +static void * +_PyObject_ArenaMmap(void *ctx, size_t size) +{ + void *ptr; + ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (ptr == MAP_FAILED) + return NULL; + assert(ptr != NULL); + return ptr; +} + +static void +_PyObject_ArenaMunmap(void *ctx, void *ptr, size_t size) +{ + munmap(ptr, size); +} + +#else +static void * +_PyObject_ArenaMalloc(void *ctx, size_t size) +{ + return malloc(size); +} + +static void +_PyObject_ArenaFree(void *ctx, void *ptr, size_t size) +{ + free(ptr); +} #endif + +#define PYRAW_FUNCS _PyMem_RawMalloc, _PyMem_RawRealloc, _PyMem_RawFree +#ifdef WITH_PYMALLOC +#define PYOBJECT_FUNCS _PyObject_Malloc, _PyObject_Realloc, _PyObject_Free +#else +#define PYOBJECT_FUNCS PYRAW_FUNCS +#endif + +#ifdef PYMALLOC_DEBUG +typedef struct { + /* We tag each block with an API ID in order to tag API violations */ + char api_id; + PyMemAllocator alloc; +} debug_alloc_api_t; +static struct { + debug_alloc_api_t raw; + debug_alloc_api_t mem; + debug_alloc_api_t obj; +} _PyMem_Debug = { + {'r', {NULL, PYRAW_FUNCS}}, + {'m', {NULL, PYRAW_FUNCS}}, + {'o', {NULL, PYOBJECT_FUNCS}} + }; + +#define PYDEBUG_FUNCS _PyMem_DebugMalloc, _PyMem_DebugRealloc, _PyMem_DebugFree +#endif + +static PyMemAllocator _PyMem_Raw = { +#ifdef PYMALLOC_DEBUG + &_PyMem_Debug.raw, PYDEBUG_FUNCS +#else + NULL, PYRAW_FUNCS +#endif + }; + +static PyMemAllocator _PyMem = { +#ifdef PYMALLOC_DEBUG + &_PyMem_Debug.mem, PYDEBUG_FUNCS +#else + NULL, PYRAW_FUNCS +#endif + }; + +static PyMemAllocator _PyObject = { +#ifdef PYMALLOC_DEBUG + &_PyMem_Debug.obj, PYDEBUG_FUNCS +#else + NULL, PYOBJECT_FUNCS +#endif + }; + +#undef PYRAW_FUNCS +#undef PYOBJECT_FUNCS +#undef PYDEBUG_FUNCS + +static PyObjectArenaAllocator _PyObject_Arena = {NULL, +#ifdef MS_WINDOWS + _PyObject_ArenaVirtualAlloc, _PyObject_ArenaVirtualFree +#elif defined(ARENAS_USE_MMAP) + _PyObject_ArenaMmap, _PyObject_ArenaMunmap +#else + _PyObject_ArenaMalloc, _PyObject_ArenaFree +#endif + }; + +void +PyMem_SetupDebugHooks(void) +{ +#ifdef PYMALLOC_DEBUG + PyMemAllocator alloc; + + alloc.malloc = _PyMem_DebugMalloc; + alloc.realloc = _PyMem_DebugRealloc; + alloc.free = _PyMem_DebugFree; + + if (_PyMem_Raw.malloc != _PyMem_DebugMalloc) { + alloc.ctx = &_PyMem_Debug.raw; + PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &_PyMem_Debug.raw.alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); + } + + if (_PyMem.malloc != _PyMem_DebugMalloc) { + alloc.ctx = &_PyMem_Debug.mem; + PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &_PyMem_Debug.mem.alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); + } + + if (_PyObject.malloc != _PyMem_DebugMalloc) { + alloc.ctx = &_PyMem_Debug.obj; + PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &_PyMem_Debug.obj.alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); + } +#endif +} + +void +PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator) +{ + switch(domain) + { + case PYMEM_DOMAIN_RAW: *allocator = _PyMem_Raw; break; + case PYMEM_DOMAIN_MEM: *allocator = _PyMem; break; + case PYMEM_DOMAIN_OBJ: *allocator = _PyObject; break; + default: + /* unknown domain */ + allocator->ctx = NULL; + allocator->malloc = NULL; + allocator->realloc = NULL; + allocator->free = NULL; + } +} + +void +PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator) +{ + switch(domain) + { + case PYMEM_DOMAIN_RAW: _PyMem_Raw = *allocator; break; + case PYMEM_DOMAIN_MEM: _PyMem = *allocator; break; + case PYMEM_DOMAIN_OBJ: _PyObject = *allocator; break; + /* ignore unknown domain */ + } + +} + +void +PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator) +{ + *allocator = _PyObject_Arena; +} + +void +PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator) +{ + _PyObject_Arena = *allocator; +} + +void * +PyMem_RawMalloc(size_t size) +{ + /* + * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes. + * Most python internals blindly use a signed Py_ssize_t to track + * things without checking for overflows or negatives. + * As size_t is unsigned, checking for size < 0 is not required. + */ + if (size > (size_t)PY_SSIZE_T_MAX) + return NULL; + + return _PyMem_Raw.malloc(_PyMem_Raw.ctx, size); +} + +void* +PyMem_RawRealloc(void *ptr, size_t new_size) +{ + /* see PyMem_RawMalloc() */ + if (new_size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyMem_Raw.realloc(_PyMem_Raw.ctx, ptr, new_size); +} + +void PyMem_RawFree(void *ptr) +{ + _PyMem_Raw.free(_PyMem_Raw.ctx, ptr); +} + +void * +PyMem_Malloc(size_t size) +{ + /* see PyMem_RawMalloc() */ + if (size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyMem.malloc(_PyMem.ctx, size); +} + +void * +PyMem_Realloc(void *ptr, size_t new_size) +{ + /* see PyMem_RawMalloc() */ + if (new_size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyMem.realloc(_PyMem.ctx, ptr, new_size); +} + +void +PyMem_Free(void *ptr) +{ + _PyMem.free(_PyMem.ctx, ptr); +} + +void * +PyObject_Malloc(size_t size) +{ + /* see PyMem_RawMalloc() */ + if (size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyObject.malloc(_PyObject.ctx, size); +} + +void * +PyObject_Realloc(void *ptr, size_t new_size) +{ + /* see PyMem_RawMalloc() */ + if (new_size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyObject.realloc(_PyObject.ctx, ptr, new_size); +} + +void +PyObject_Free(void *ptr) +{ + _PyObject.free(_PyObject.ctx, ptr); +} + + +#ifdef WITH_PYMALLOC + #ifdef WITH_VALGRIND #include @@ -549,7 +857,6 @@ struct arena_object* arenaobj; uint excess; /* number of bytes above pool alignment */ void *address; - int err; #ifdef PYMALLOC_DEBUG if (Py_GETENV("PYTHONMALLOCSTATS")) @@ -571,7 +878,7 @@ return NULL; /* overflow */ #endif nbytes = numarenas * sizeof(*arenas); - arenaobj = (struct arena_object *)realloc(arenas, nbytes); + arenaobj = (struct arena_object *)PyMem_Realloc(arenas, nbytes); if (arenaobj == NULL) return NULL; arenas = arenaobj; @@ -602,19 +909,8 @@ arenaobj = unused_arena_objects; unused_arena_objects = arenaobj->nextarena; assert(arenaobj->address == 0); -#ifdef MS_WINDOWS - address = (void*)VirtualAlloc(NULL, ARENA_SIZE, - MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - err = (address == NULL); -#elif defined(ARENAS_USE_MMAP) - address = mmap(NULL, ARENA_SIZE, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - err = (address == MAP_FAILED); -#else - address = malloc(ARENA_SIZE); - err = (address == 0); -#endif - if (err) { + address = _PyObject_Arena.alloc(_PyObject_Arena.ctx, ARENA_SIZE); + if (address == NULL) { /* The allocation failed: return NULL after putting the * arenaobj back. */ @@ -777,9 +1073,8 @@ * Unless the optimizer reorders everything, being too smart... */ -#undef PyObject_Malloc -void * -PyObject_Malloc(size_t nbytes) +static void * +_PyObject_Malloc(void *ctx, size_t nbytes) { block *bp; poolp pool; @@ -796,17 +1091,6 @@ #endif /* - * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes. - * Most python internals blindly use a signed Py_ssize_t to track - * things without checking for overflows or negatives. - * As size_t is unsigned, checking for nbytes < 0 is not required. - */ - if (nbytes > PY_SSIZE_T_MAX) { - _Py_AllocatedBlocks--; - return NULL; - } - - /* * This implicitly redirects malloc(0). */ if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) { @@ -978,10 +1262,8 @@ * last chance to serve the request) or when the max memory limit * has been reached. */ - if (nbytes == 0) - nbytes = 1; { - void *result = malloc(nbytes); + void *result = PyMem_Malloc(nbytes); if (!result) _Py_AllocatedBlocks--; return result; @@ -990,9 +1272,8 @@ /* free */ -#undef PyObject_Free -void -PyObject_Free(void *p) +static void +_PyObject_Free(void *ctx, void *p) { poolp pool; block *lastfree; @@ -1101,13 +1382,8 @@ unused_arena_objects = ao; /* Free the entire arena. */ -#ifdef MS_WINDOWS - VirtualFree((void *)ao->address, 0, MEM_RELEASE); -#elif defined(ARENAS_USE_MMAP) - munmap((void *)ao->address, ARENA_SIZE); -#else - free((void *)ao->address); -#endif + _PyObject_Arena.free(_PyObject_Arena.ctx, + (void *)ao->address, ARENA_SIZE); ao->address = 0; /* mark unassociated */ --narenas_currently_allocated; @@ -1216,7 +1492,7 @@ redirect: #endif /* We didn't allocate this address. */ - free(p); + PyMem_Free(p); } /* realloc. If p is NULL, this acts like malloc(nbytes). Else if nbytes==0, @@ -1224,9 +1500,8 @@ * return a non-NULL result. */ -#undef PyObject_Realloc -void * -PyObject_Realloc(void *p, size_t nbytes) +static void * +_PyObject_Realloc(void *ctx, void *p, size_t nbytes) { void *bp; poolp pool; @@ -1236,16 +1511,7 @@ #endif if (p == NULL) - return PyObject_Malloc(nbytes); - - /* - * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes. - * Most python internals blindly use a signed Py_ssize_t to track - * things without checking for overflows or negatives. - * As size_t is unsigned, checking for nbytes < 0 is not required. - */ - if (nbytes > PY_SSIZE_T_MAX) - return NULL; + return _PyObject_Malloc(ctx, nbytes); #ifdef WITH_VALGRIND /* Treat running_on_valgrind == -1 the same as 0 */ @@ -1273,10 +1539,10 @@ } size = nbytes; } - bp = PyObject_Malloc(nbytes); + bp = _PyObject_Malloc(ctx, nbytes); if (bp != NULL) { memcpy(bp, p, size); - PyObject_Free(p); + _PyObject_Free(ctx, p); } return bp; } @@ -1294,14 +1560,14 @@ * at p. Instead we punt: let C continue to manage this block. */ if (nbytes) - return realloc(p, nbytes); + return PyMem_Realloc(p, nbytes); /* C doesn't define the result of realloc(p, 0) (it may or may not * return NULL then), but Python's docs promise that nbytes==0 never * returns NULL. We don't pass 0 to realloc(), to avoid that endcase * to begin with. Even then, we can't be sure that realloc() won't * return NULL. */ - bp = realloc(p, 1); + bp = PyMem_Realloc(p, 1); return bp ? bp : p; } @@ -1311,24 +1577,6 @@ /* pymalloc not enabled: Redirect the entry points to malloc. These will * only be used by extensions that are compiled with pymalloc enabled. */ -void * -PyObject_Malloc(size_t n) -{ - return PyMem_MALLOC(n); -} - -void * -PyObject_Realloc(void *p, size_t n) -{ - return PyMem_REALLOC(p, n); -} - -void -PyObject_Free(void *p) -{ - PyMem_FREE(p); -} - Py_ssize_t _Py_GetAllocatedBlocks(void) { @@ -1354,10 +1602,6 @@ #define DEADBYTE 0xDB /* dead (newly freed) memory */ #define FORBIDDENBYTE 0xFB /* untouchable bytes at each end of a block */ -/* We tag each block with an API ID in order to tag API violations */ -#define _PYMALLOC_MEM_ID 'm' /* the PyMem_Malloc() API */ -#define _PYMALLOC_OBJ_ID 'o' /* The PyObject_Malloc() API */ - static size_t serialno = 0; /* incremented on each debug {m,re}alloc */ /* serialno is always incremented via calling this routine. The point is @@ -1440,58 +1684,18 @@ p[2*S+n: 2*S+n+S] Copies of FORBIDDENBYTE. Used to catch over- writes and reads. p[2*S+n+S: 2*S+n+2*S] - A serial number, incremented by 1 on each call to _PyObject_DebugMalloc - and _PyObject_DebugRealloc. + A serial number, incremented by 1 on each call to _PyMem_DebugMalloc + and _PyMem_DebugRealloc. This is a big-endian size_t. If "bad memory" is detected later, the serial number gives an excellent way to set a breakpoint on the next run, to capture the instant at which this block was passed out. */ -/* debug replacements for the PyMem_* memory API */ -void * -_PyMem_DebugMalloc(size_t nbytes) +static void * +_PyMem_DebugMalloc(void *ctx, size_t nbytes) { - return _PyObject_DebugMallocApi(_PYMALLOC_MEM_ID, nbytes); -} -void * -_PyMem_DebugRealloc(void *p, size_t nbytes) -{ - return _PyObject_DebugReallocApi(_PYMALLOC_MEM_ID, p, nbytes); -} -void -_PyMem_DebugFree(void *p) -{ - _PyObject_DebugFreeApi(_PYMALLOC_MEM_ID, p); -} - -/* debug replacements for the PyObject_* memory API */ -void * -_PyObject_DebugMalloc(size_t nbytes) -{ - return _PyObject_DebugMallocApi(_PYMALLOC_OBJ_ID, nbytes); -} -void * -_PyObject_DebugRealloc(void *p, size_t nbytes) -{ - return _PyObject_DebugReallocApi(_PYMALLOC_OBJ_ID, p, nbytes); -} -void -_PyObject_DebugFree(void *p) -{ - _PyObject_DebugFreeApi(_PYMALLOC_OBJ_ID, p); -} -void -_PyObject_DebugCheckAddress(const void *p) -{ - _PyObject_DebugCheckAddressApi(_PYMALLOC_OBJ_ID, p); -} - - -/* generic debug memory api, with an "id" to identify the API in use */ -void * -_PyObject_DebugMallocApi(char id, size_t nbytes) -{ + debug_alloc_api_t *api = (debug_alloc_api_t *)ctx; uchar *p; /* base address of malloc'ed block */ uchar *tail; /* p + 2*SST + nbytes == pointer to tail pad bytes */ size_t total; /* nbytes + 4*SST */ @@ -1502,14 +1706,14 @@ /* overflow: can't represent total as a size_t */ return NULL; - p = (uchar *)PyObject_Malloc(total); + p = (uchar *)api->alloc.malloc(api->alloc.ctx, total); if (p == NULL) return NULL; /* at p, write size (SST bytes), id (1 byte), pad (SST-1 bytes) */ write_size_t(p, nbytes); - p[SST] = (uchar)id; - memset(p + SST + 1 , FORBIDDENBYTE, SST-1); + p[SST] = (uchar)api->api_id; + memset(p + SST + 1, FORBIDDENBYTE, SST-1); if (nbytes > 0) memset(p + 2*SST, CLEANBYTE, nbytes); @@ -1527,25 +1731,27 @@ Then fills the original bytes with DEADBYTE. Then calls the underlying free. */ -void -_PyObject_DebugFreeApi(char api, void *p) +static void +_PyMem_DebugFree(void *ctx, void *p) { + debug_alloc_api_t *api = (debug_alloc_api_t *)ctx; uchar *q = (uchar *)p - 2*SST; /* address returned from malloc */ size_t nbytes; if (p == NULL) return; - _PyObject_DebugCheckAddressApi(api, p); + _PyMem_DebugCheckAddress(api->api_id, p); nbytes = read_size_t(q); nbytes += 4*SST; if (nbytes > 0) memset(q, DEADBYTE, nbytes); - PyObject_Free(q); + api->alloc.free(api->alloc.ctx, q); } -void * -_PyObject_DebugReallocApi(char api, void *p, size_t nbytes) +static void * +_PyMem_DebugRealloc(void *ctx, void *p, size_t nbytes) { + debug_alloc_api_t *api = (debug_alloc_api_t *)ctx; uchar *q = (uchar *)p; uchar *tail; size_t total; /* nbytes + 4*SST */ @@ -1553,9 +1759,9 @@ int i; if (p == NULL) - return _PyObject_DebugMallocApi(api, nbytes); + return _PyMem_DebugMalloc(ctx, nbytes); - _PyObject_DebugCheckAddressApi(api, p); + _PyMem_DebugCheckAddress(api->api_id, p); bumpserialno(); original_nbytes = read_size_t(q - 2*SST); total = nbytes + 4*SST; @@ -1572,12 +1778,12 @@ * case we didn't get the chance to mark the old memory with DEADBYTE, * but we live with that. */ - q = (uchar *)PyObject_Realloc(q - 2*SST, total); + q = (uchar *)api->alloc.realloc(api->alloc.ctx, q - 2*SST, total); if (q == NULL) return NULL; write_size_t(q, nbytes); - assert(q[SST] == (uchar)api); + assert(q[SST] == (uchar)api->api_id); for (i = 1; i < SST; ++i) assert(q[SST + i] == FORBIDDENBYTE); q += 2*SST; @@ -1599,8 +1805,8 @@ * and call Py_FatalError to kill the program. * The API id, is also checked. */ - void -_PyObject_DebugCheckAddressApi(char api, const void *p) +static void +_PyMem_DebugCheckAddress(char api, const void *p) { const uchar *q = (const uchar *)p; char msgbuf[64]; @@ -1652,7 +1858,7 @@ } /* Display info to stderr about the memory block at p. */ -void +static void _PyObject_DebugDumpAddress(const void *p) { const uchar *q = (const uchar *)p; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 02:50:07 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 02:50:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317206=3A_On_Windo?= =?utf-8?q?ws=2C_increase_the_stack_size_from_2_MB_to_4=2E2_MB_to_fix?= Message-ID: <3bnrmb2gtdz7LjW@mail.python.org> http://hg.python.org/cpython/rev/fcf079dece0d changeset: 84472:fcf079dece0d user: Victor Stinner date: Sun Jul 07 02:49:07 2013 +0200 summary: Issue #17206: On Windows, increase the stack size from 2 MB to 4.2 MB to fix a stack overflow in the marshal module (fix a crash in test_marshal). Patch written by Jeremy Kloth. files: Misc/NEWS | 4 ++++ PCbuild/python.vcxproj | 2 +- 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #17206: On Windows, increase the stack size from 2 MB to 4.2 MB to fix + a stack overflow in the marshal module (fix a crash in test_marshal). + Patch written by Jeremy Kloth. + - Issue #3329: Implement the PEP 445: Add new APIs to customize Python memory allocators. diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -243,7 +243,7 @@ $(OutDir)python_d.exe Console - 2100000 + 4194304 0x1d000000 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 03:06:31 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 03:06:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=233329=3A_Fix_=5FPy?= =?utf-8?q?Object=5FArenaVirtualFree=28=29?= Message-ID: <3bns7W2Fvbz7LkR@mail.python.org> http://hg.python.org/cpython/rev/51ed51d10e60 changeset: 84473:51ed51d10e60 user: Victor Stinner date: Sun Jul 07 03:06:16 2013 +0200 summary: Issue #3329: Fix _PyObject_ArenaVirtualFree() According to VirtualFree() documentation, the size must be zero if the "free type" is MEM_RELEASE. files: Objects/obmalloc.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -68,7 +68,7 @@ static void _PyObject_ArenaVirtualFree(void *ctx, void *ptr, size_t size) { - VirtualFree(ptr, size, MEM_RELEASE); + VirtualFree(ptr, 0, MEM_RELEASE); } #elif defined(ARENAS_USE_MMAP) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 7 05:46:07 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 07 Jul 2013 05:46:07 +0200 Subject: [Python-checkins] Daily reference leaks (51ed51d10e60): sum=5 Message-ID: results for 51ed51d10e60 on branch "default" -------------------------------------------- test_support leaked [1, 0, 0] references, sum=1 test_support leaked [1, 2, 1] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog6zGxiG', '-x'] From python-checkins at python.org Sun Jul 7 05:50:11 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 7 Jul 2013 05:50:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Improve_variable_names_in_?= =?utf-8?q?deque=5Fcount=28=29?= Message-ID: <3bnwmM364Vz7LjX@mail.python.org> http://hg.python.org/cpython/rev/e7025b1e69ce changeset: 84474:e7025b1e69ce parent: 84470:9166aa413d6f user: Raymond Hettinger date: Sat Jul 06 17:49:06 2013 -1000 summary: Improve variable names in deque_count() files: Modules/_collectionsmodule.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -581,8 +581,8 @@ static PyObject * deque_count(dequeobject *deque, PyObject *v) { - block *leftblock = deque->leftblock; - Py_ssize_t leftindex = deque->leftindex; + block *b = deque->leftblock; + Py_ssize_t index = deque->leftindex; Py_ssize_t n = Py_SIZE(deque); Py_ssize_t i; Py_ssize_t count = 0; @@ -591,8 +591,8 @@ int cmp; for (i=0 ; idata[leftindex]; + assert(b != NULL); + item = b->data[index]; cmp = PyObject_RichCompareBool(item, v, Py_EQ); if (cmp > 0) count++; @@ -606,10 +606,10 @@ } /* Advance left block/index pair */ - leftindex++; - if (leftindex == BLOCKLEN) { - leftblock = leftblock->rightlink; - leftindex = 0; + index++; + if (index == BLOCKLEN) { + b = b->rightlink; + index = 0; } } return PyLong_FromSsize_t(count); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 05:50:13 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 7 Jul 2013 05:50:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bnwmP23bCz7LkC@mail.python.org> http://hg.python.org/cpython/rev/cc0c8c1c9cca changeset: 84475:cc0c8c1c9cca parent: 84474:e7025b1e69ce parent: 84473:51ed51d10e60 user: Raymond Hettinger date: Sat Jul 06 17:50:01 2013 -1000 summary: merge files: Doc/c-api/memory.rst | 171 ++++++++- Doc/whatsnew/3.4.rst | 18 +- Include/objimpl.h | 60 +- Include/pymem.h | 94 +++- Misc/NEWS | 7 + Modules/_testcapimodule.c | 163 ++++++++ Objects/object.c | 20 - Objects/obmalloc.c | 504 ++++++++++++++++++------- PCbuild/python.vcxproj | 2 +- 9 files changed, 801 insertions(+), 238 deletions(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -84,6 +84,48 @@ for the I/O buffer escapes completely the Python memory manager. +Raw Memory Interface +==================== + +The following function sets are wrappers to the system allocator. These +functions are thread-safe, the :term:`GIL ` does not +need to be held. + +The default raw memory block allocator uses the following functions: +:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when +requesting zero bytes. + +.. versionadded:: 3.4 + +.. c:function:: void* PyMem_RawMalloc(size_t n) + + Allocates *n* bytes and returns a pointer of type :c:type:`void\*` to the + allocated memory, or *NULL* if the request fails. Requesting zero bytes + returns a distinct non-*NULL* pointer if possible, as if + ``PyMem_RawMalloc(1)`` had been called instead. The memory will not have + been initialized in any way. + + +.. c:function:: void* PyMem_RawRealloc(void *p, size_t n) + + Resizes the memory block pointed to by *p* to *n* bytes. The contents will + be unchanged to the minimum of the old and the new sizes. If *p* is *NULL*, + the call is equivalent to ``PyMem_RawMalloc(n)``; else if *n* is equal to + zero, the memory block is resized but is not freed, and the returned pointer + is non-*NULL*. Unless *p* is *NULL*, it must have been returned by a + previous call to :c:func:`PyMem_RawMalloc` or :c:func:`PyMem_RawRealloc`. If + the request fails, :c:func:`PyMem_RawRealloc` returns *NULL* and *p* remains + a valid pointer to the previous memory area. + + +.. c:function:: void PyMem_RawFree(void *p) + + Frees the memory block pointed to by *p*, which must have been returned by a + previous call to :c:func:`PyMem_RawMalloc` or :c:func:`PyMem_RawRealloc`. + Otherwise, or if ``PyMem_Free(p)`` has been called before, undefined + behavior occurs. If *p* is *NULL*, no operation is performed. + + .. _memoryinterface: Memory Interface @@ -91,8 +133,16 @@ The following function sets, modeled after the ANSI C standard, but specifying behavior when requesting zero bytes, are available for allocating and releasing -memory from the Python heap: +memory from the Python heap. +The default memory block allocator uses the following functions: +:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when +requesting zero bytes. + +.. warning:: + + The :term:`GIL ` must be held when using these + functions. .. c:function:: void* PyMem_Malloc(size_t n) @@ -155,6 +205,125 @@ :c:func:`PyMem_NEW`, :c:func:`PyMem_RESIZE`, :c:func:`PyMem_DEL`. +Customize Memory Allocators +=========================== + +.. versionadded:: 3.4 + +.. c:type:: PyMemAllocator + + Structure used to describe a memory block allocator. The structure has + four fields: + + +----------------------------------------------------------+---------------------------------------+ + | Field | Meaning | + +==========================================================+=======================================+ + | ``void *ctx`` | user context passed as first argument | + +----------------------------------------------------------+---------------------------------------+ + | ``void* malloc(void *ctx, size_t size)`` | allocate a memory block | + +----------------------------------------------------------+---------------------------------------+ + | ``void* realloc(void *ctx, void *ptr, size_t new_size)`` | allocate or resize a memory block | + +----------------------------------------------------------+---------------------------------------+ + | ``void free(void *ctx, void *ptr)`` | free a memory block | + +----------------------------------------------------------+---------------------------------------+ + +.. c:type:: PyMemAllocatorDomain + + Enum used to identify an allocator domain. Domains: + + * :c:data:`PYMEM_DOMAIN_RAW`: functions :c:func:`PyMem_RawMalloc`, + :c:func:`PyMem_RawRealloc` and :c:func:`PyMem_RawFree` + * :c:data:`PYMEM_DOMAIN_MEM`: functions :c:func:`PyMem_Malloc`, + :c:func:`PyMem_Realloc` and :c:func:`PyMem_Free` + * :c:data:`PYMEM_DOMAIN_OBJ`: functions :c:func:`PyObject_Malloc`, + :c:func:`PyObject_Realloc` and :c:func:`PyObject_Free` + + +.. c:function:: void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator) + + Get the memory block allocator of the specified domain. + + +.. c:function:: void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator) + + Set the memory block allocator of the specified domain. + + The new allocator must return a distinct non-NULL pointer when requesting + zero bytes. + + For the :c:data:`PYMEM_DOMAIN_RAW` domain, the allocator must be + thread-safe: the :term:`GIL ` is not held when the + allocator is called. + + If the new allocator is not a hook (does not call the previous allocator), + the :c:func:`PyMem_SetupDebugHooks` function must be called to reinstall the + debug hooks on top on the new allocator. + + +.. c:function:: void PyMem_SetupDebugHooks(void) + + Setup hooks to detect bugs in the following Python memory allocator + functions: + + - :c:func:`PyMem_RawMalloc`, :c:func:`PyMem_RawRealloc`, + :c:func:`PyMem_RawFree` + - :c:func:`PyMem_Malloc`, :c:func:`PyMem_Realloc`, :c:func:`PyMem_Free` + - :c:func:`PyObject_Malloc`, :c:func:`PyObject_Realloc`, + :c:func:`PyObject_Free` + + Newly allocated memory is filled with the byte ``0xCB``, freed memory is + filled with the byte ``0xDB``. Additionnal checks: + + - detect API violations, ex: :c:func:`PyObject_Free` called on a buffer + allocated by :c:func:`PyMem_Malloc` + - detect write before the start of the buffer (buffer underflow) + - detect write after the end of the buffer (buffer overflow) + + The function does nothing if Python is not compiled is debug mode. + + +Customize PyObject Arena Allocator +================================== + +Python has a *pymalloc* allocator for allocations smaller than 512 bytes. This +allocator is optimized for small objects with a short lifetime. It uses memory +mappings called "arenas" with a fixed size of 256 KB. It falls back to +:c:func:`PyMem_Malloc` and :c:func:`PyMem_Realloc` for allocations larger than +512 bytes. *pymalloc* is the default allocator used by +:c:func:`PyObject_Malloc`. + +The default arena allocator uses the following functions: + +* :c:func:`VirtualAlloc` and :c:func:`VirtualFree` on Windows, +* :c:func:`mmap` and :c:func:`munmap` if available, +* :c:func:`malloc` and :c:func:`free` otherwise. + +.. versionadded:: 3.4 + +.. c:type:: PyObjectArenaAllocator + + Structure used to describe an arena allocator. The structure has + three fields: + + +--------------------------------------------------+---------------------------------------+ + | Field | Meaning | + +==================================================+=======================================+ + | ``void *ctx`` | user context passed as first argument | + +--------------------------------------------------+---------------------------------------+ + | ``void* alloc(void *ctx, size_t size)`` | allocate an arena of size bytes | + +--------------------------------------------------+---------------------------------------+ + | ``void free(void *ctx, size_t size, void *ptr)`` | free an arena | + +--------------------------------------------------+---------------------------------------+ + +.. c:function:: PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator) + + Get the arena allocator. + +.. c:function:: PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator) + + Set the arena allocator. + + .. _memoryexamples: Examples 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 @@ -112,21 +112,11 @@ Please read on for a comprehensive list of user-facing changes. -.. PEP-sized items next. +PEP 445: Add new APIs to customize Python memory allocators +=========================================================== -.. _pep-4XX: - -.. PEP 4XX: Example PEP -.. ==================== - - -.. (Implemented by Foo Bar.) - -.. .. seealso:: - - :pep:`4XX` - Example PEP - PEP written by Example Author - +The :pep:`445` adds new Application Programming Interfaces (API) to customize +Python memory allocators. diff --git a/Include/objimpl.h b/Include/objimpl.h --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -94,9 +94,9 @@ the object gets initialized via PyObject_{Init, InitVar} after obtaining the raw memory. */ -PyAPI_FUNC(void *) PyObject_Malloc(size_t); -PyAPI_FUNC(void *) PyObject_Realloc(void *, size_t); -PyAPI_FUNC(void) PyObject_Free(void *); +PyAPI_FUNC(void *) PyObject_Malloc(size_t size); +PyAPI_FUNC(void *) PyObject_Realloc(void *ptr, size_t new_size); +PyAPI_FUNC(void) PyObject_Free(void *ptr); /* This function returns the number of allocated memory blocks, regardless of size */ PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void); @@ -106,41 +106,15 @@ #ifndef Py_LIMITED_API PyAPI_FUNC(void) _PyObject_DebugMallocStats(FILE *out); #endif /* #ifndef Py_LIMITED_API */ -#ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */ -PyAPI_FUNC(void *) _PyObject_DebugMalloc(size_t nbytes); -PyAPI_FUNC(void *) _PyObject_DebugRealloc(void *p, size_t nbytes); -PyAPI_FUNC(void) _PyObject_DebugFree(void *p); -PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p); -PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p); -PyAPI_FUNC(void *) _PyObject_DebugMallocApi(char api, size_t nbytes); -PyAPI_FUNC(void *) _PyObject_DebugReallocApi(char api, void *p, size_t nbytes); -PyAPI_FUNC(void) _PyObject_DebugFreeApi(char api, void *p); -PyAPI_FUNC(void) _PyObject_DebugCheckAddressApi(char api, const void *p); -PyAPI_FUNC(void *) _PyMem_DebugMalloc(size_t nbytes); -PyAPI_FUNC(void *) _PyMem_DebugRealloc(void *p, size_t nbytes); -PyAPI_FUNC(void) _PyMem_DebugFree(void *p); -#define PyObject_MALLOC _PyObject_DebugMalloc -#define PyObject_Malloc _PyObject_DebugMalloc -#define PyObject_REALLOC _PyObject_DebugRealloc -#define PyObject_Realloc _PyObject_DebugRealloc -#define PyObject_FREE _PyObject_DebugFree -#define PyObject_Free _PyObject_DebugFree +#endif -#else /* WITH_PYMALLOC && ! PYMALLOC_DEBUG */ +/* Macros */ #define PyObject_MALLOC PyObject_Malloc #define PyObject_REALLOC PyObject_Realloc #define PyObject_FREE PyObject_Free -#endif +#define PyObject_Del PyObject_Free +#define PyObject_DEL PyObject_Free -#else /* ! WITH_PYMALLOC */ -#define PyObject_MALLOC PyMem_MALLOC -#define PyObject_REALLOC PyMem_REALLOC -#define PyObject_FREE PyMem_FREE - -#endif /* WITH_PYMALLOC */ - -#define PyObject_Del PyObject_Free -#define PyObject_DEL PyObject_FREE /* * Generic object allocator interface @@ -224,6 +198,26 @@ constructor you would start directly with PyObject_Init/InitVar */ +#ifndef Py_LIMITED_API +typedef struct { + /* user context passed as the first argument to the 2 functions */ + void *ctx; + + /* allocate an arena of size bytes */ + void* (*alloc) (void *ctx, size_t size); + + /* free an arena */ + void (*free) (void *ctx, void *ptr, size_t size); +} PyObjectArenaAllocator; + +/* Get the arena allocator. */ +PyAPI_FUNC(void) PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator); + +/* Set the arena allocator. */ +PyAPI_FUNC(void) PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator); +#endif + + /* * Garbage Collection Support * ========================== diff --git a/Include/pymem.h b/Include/pymem.h --- a/Include/pymem.h +++ b/Include/pymem.h @@ -11,6 +11,11 @@ extern "C" { #endif +PyAPI_FUNC(void *) PyMem_RawMalloc(size_t size); +PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size); +PyAPI_FUNC(void) PyMem_RawFree(void *ptr); + + /* BEWARE: Each interface exports both functions and macros. Extension modules should @@ -49,21 +54,11 @@ performed on failure (no exception is set, no warning is printed, etc). */ -PyAPI_FUNC(void *) PyMem_Malloc(size_t); -PyAPI_FUNC(void *) PyMem_Realloc(void *, size_t); -PyAPI_FUNC(void) PyMem_Free(void *); - -/* Starting from Python 1.6, the wrappers Py_{Malloc,Realloc,Free} are - no longer supported. They used to call PyErr_NoMemory() on failure. */ +PyAPI_FUNC(void *) PyMem_Malloc(size_t size); +PyAPI_FUNC(void *) PyMem_Realloc(void *ptr, size_t new_size); +PyAPI_FUNC(void) PyMem_Free(void *ptr); /* Macros. */ -#ifdef PYMALLOC_DEBUG -/* Redirect all memory operations to Python's debugging allocator. */ -#define PyMem_MALLOC _PyMem_DebugMalloc -#define PyMem_REALLOC _PyMem_DebugRealloc -#define PyMem_FREE _PyMem_DebugFree - -#else /* ! PYMALLOC_DEBUG */ /* PyMem_MALLOC(0) means malloc(1). Some systems would return NULL for malloc(0), which would be treated as an error. Some platforms @@ -71,13 +66,9 @@ pymalloc. To solve these problems, allocate an extra byte. */ /* Returns NULL to indicate error if a negative size or size larger than Py_ssize_t can represent is supplied. Helps prevents security holes. */ -#define PyMem_MALLOC(n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \ - : malloc((n) ? (n) : 1)) -#define PyMem_REALLOC(p, n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \ - : realloc((p), (n) ? (n) : 1)) -#define PyMem_FREE free - -#endif /* PYMALLOC_DEBUG */ +#define PyMem_MALLOC(n) PyMem_Malloc(n) +#define PyMem_REALLOC(p, n) PyMem_Realloc(p, n) +#define PyMem_FREE(p) PyMem_Free(p) /* * Type-oriented memory interface @@ -115,6 +106,69 @@ #define PyMem_Del PyMem_Free #define PyMem_DEL PyMem_FREE +#ifndef Py_LIMITED_API +typedef enum { + /* PyMem_RawMalloc(), PyMem_RawRealloc() and PyMem_RawFree() */ + PYMEM_DOMAIN_RAW, + + /* PyMem_Malloc(), PyMem_Realloc() and PyMem_Free() */ + PYMEM_DOMAIN_MEM, + + /* PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() */ + PYMEM_DOMAIN_OBJ +} PyMemAllocatorDomain; + +typedef struct { + /* user context passed as the first argument to the 3 functions */ + void *ctx; + + /* allocate a memory block */ + void* (*malloc) (void *ctx, size_t size); + + /* allocate or resize a memory block */ + void* (*realloc) (void *ctx, void *ptr, size_t new_size); + + /* release a memory block */ + void (*free) (void *ctx, void *ptr); +} PyMemAllocator; + +/* Get the memory block allocator of the specified domain. */ +PyAPI_FUNC(void) PyMem_GetAllocator(PyMemAllocatorDomain domain, + PyMemAllocator *allocator); + +/* Set the memory block allocator of the specified domain. + + The new allocator must return a distinct non-NULL pointer when requesting + zero bytes. + + For the PYMEM_DOMAIN_RAW domain, the allocator must be thread-safe: the GIL + is not held when the allocator is called. + + If the new allocator is not a hook (don't call the previous allocator), the + PyMem_SetupDebugHooks() function must be called to reinstall the debug hooks + on top on the new allocator. */ +PyAPI_FUNC(void) PyMem_SetAllocator(PyMemAllocatorDomain domain, + PyMemAllocator *allocator); + +/* Setup hooks to detect bugs in the following Python memory allocator + functions: + + - PyMem_RawMalloc(), PyMem_RawRealloc(), PyMem_RawFree() + - PyMem_Malloc(), PyMem_Realloc(), PyMem_Free() + - PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() + + Newly allocated memory is filled with the byte 0xCB, freed memory is filled + with the byte 0xDB. Additionnal checks: + + - detect API violations, ex: PyObject_Free() called on a buffer allocated + by PyMem_Malloc() + - detect write before the start of the buffer (buffer underflow) + - detect write after the end of the buffer (buffer overflow) + + The function does nothing if Python is not compiled is debug mode. */ +PyAPI_FUNC(void) PyMem_SetupDebugHooks(void); +#endif + #ifdef __cplusplus } #endif diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,13 @@ Core and Builtins ----------------- +- Issue #17206: On Windows, increase the stack size from 2 MB to 4.2 MB to fix + a stack overflow in the marshal module (fix a crash in test_marshal). + Patch written by Jeremy Kloth. + +- Issue #3329: Implement the PEP 445: Add new APIs to customize Python memory + allocators. + - Issue #18328: Reorder ops in PyThreadState_Delete*() functions. Now the tstate is first removed from TLS and then deallocated. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2511,6 +2511,161 @@ Py_RETURN_NONE; } +static PyObject * +test_pymem_alloc0(PyObject *self) +{ + void *ptr; + + ptr = PyMem_Malloc(0); + if (ptr == NULL) { + PyErr_SetString(PyExc_RuntimeError, "PyMem_Malloc(0) returns NULL"); + return NULL; + } + PyMem_Free(ptr); + + ptr = PyObject_Malloc(0); + if (ptr == NULL) { + PyErr_SetString(PyExc_RuntimeError, "PyObject_Malloc(0) returns NULL"); + return NULL; + } + PyObject_Free(ptr); + + Py_RETURN_NONE; +} + +typedef struct { + PyMemAllocator alloc; + + size_t malloc_size; + void *realloc_ptr; + size_t realloc_new_size; + void *free_ptr; +} alloc_hook_t; + +static void* hook_malloc (void* ctx, size_t size) +{ + alloc_hook_t *hook = (alloc_hook_t *)ctx; + hook->malloc_size = size; + return hook->alloc.malloc(hook->alloc.ctx, size); +} + +static void* hook_realloc (void* ctx, void* ptr, size_t new_size) +{ + alloc_hook_t *hook = (alloc_hook_t *)ctx; + hook->realloc_ptr = ptr; + hook->realloc_new_size = new_size; + return hook->alloc.realloc(hook->alloc.ctx, ptr, new_size); +} + +static void hook_free (void *ctx, void *ptr) +{ + alloc_hook_t *hook = (alloc_hook_t *)ctx; + hook->free_ptr = ptr; + hook->alloc.free(hook->alloc.ctx, ptr); +} + +static PyObject * +test_setallocators(PyMemAllocatorDomain domain) +{ + PyObject *res = NULL; + const char *error_msg; + alloc_hook_t hook; + PyMemAllocator alloc; + size_t size, size2; + void *ptr, *ptr2; + + hook.malloc_size = 0; + hook.realloc_ptr = NULL; + hook.realloc_new_size = 0; + hook.free_ptr = NULL; + + alloc.ctx = &hook; + alloc.malloc = &hook_malloc; + alloc.realloc = &hook_realloc; + alloc.free = &hook_free; + PyMem_GetAllocator(domain, &hook.alloc); + PyMem_SetAllocator(domain, &alloc); + + size = 42; + switch(domain) + { + case PYMEM_DOMAIN_RAW: ptr = PyMem_RawMalloc(size); break; + case PYMEM_DOMAIN_MEM: ptr = PyMem_Malloc(size); break; + case PYMEM_DOMAIN_OBJ: ptr = PyObject_Malloc(size); break; + default: ptr = NULL; break; + } + + if (ptr == NULL) { + error_msg = "malloc failed"; + goto fail; + } + + if (hook.malloc_size != size) { + error_msg = "malloc invalid size"; + goto fail; + } + + size2 = 200; + switch(domain) + { + case PYMEM_DOMAIN_RAW: ptr2 = PyMem_RawRealloc(ptr, size2); break; + case PYMEM_DOMAIN_MEM: ptr2 = PyMem_Realloc(ptr, size2); break; + case PYMEM_DOMAIN_OBJ: ptr2 = PyObject_Realloc(ptr, size2); break; + } + + if (ptr2 == NULL) { + error_msg = "realloc failed"; + goto fail; + } + + if (hook.realloc_ptr != ptr + || hook.realloc_new_size != size2) { + error_msg = "realloc invalid parameters"; + goto fail; + } + + switch(domain) + { + case PYMEM_DOMAIN_RAW: PyMem_RawFree(ptr2); break; + case PYMEM_DOMAIN_MEM: PyMem_Free(ptr2); break; + case PYMEM_DOMAIN_OBJ: PyObject_Free(ptr2); break; + } + + if (hook.free_ptr != ptr2) { + error_msg = "free invalid pointer"; + goto fail; + } + + Py_INCREF(Py_None); + res = Py_None; + goto finally; + +fail: + PyErr_SetString(PyExc_RuntimeError, error_msg); + +finally: + PyMem_SetAllocator(domain, &hook.alloc); + return res; +} + +static PyObject * +test_pymem_setrawallocators(PyObject *self) +{ + return test_setallocators(PYMEM_DOMAIN_RAW); +} + +static PyObject * +test_pymem_setallocators(PyObject *self) +{ + return test_setallocators(PYMEM_DOMAIN_MEM); +} + +static PyObject * +test_pyobject_setallocators(PyObject *self) +{ + return test_setallocators(PYMEM_DOMAIN_OBJ); +} + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS}, @@ -2611,6 +2766,14 @@ {"pytime_object_to_time_t", test_pytime_object_to_time_t, METH_VARARGS}, {"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS}, {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, + {"test_pymem", + (PyCFunction)test_pymem_alloc0, METH_NOARGS}, + {"test_pymem_alloc0", + (PyCFunction)test_pymem_setrawallocators, METH_NOARGS}, + {"test_pymem_setallocators", + (PyCFunction)test_pymem_setallocators, METH_NOARGS}, + {"test_pyobject_setallocators", + (PyCFunction)test_pyobject_setallocators, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -1859,26 +1859,6 @@ Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size; -/* Python's malloc wrappers (see pymem.h) */ - -void * -PyMem_Malloc(size_t nbytes) -{ - return PyMem_MALLOC(nbytes); -} - -void * -PyMem_Realloc(void *p, size_t nbytes) -{ - return PyMem_REALLOC(p, nbytes); -} - -void -PyMem_Free(void *p) -{ - PyMem_FREE(p); -} - void _PyObject_DebugTypeStats(FILE *out) { diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -1,18 +1,326 @@ #include "Python.h" +/* Python's malloc wrappers (see pymem.h) */ + +#ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */ +/* Forward declaration */ +static void* _PyMem_DebugMalloc(void *ctx, size_t size); +static void _PyMem_DebugFree(void *ctx, void *p); +static void* _PyMem_DebugRealloc(void *ctx, void *ptr, size_t size); + +static void _PyObject_DebugDumpAddress(const void *p); +static void _PyMem_DebugCheckAddress(char api_id, const void *p); +#endif + #ifdef WITH_PYMALLOC -#ifdef HAVE_MMAP - #include - #ifdef MAP_ANONYMOUS - #define ARENAS_USE_MMAP - #endif +#ifdef MS_WINDOWS +# include +#elif defined(HAVE_MMAP) +# include +# ifdef MAP_ANONYMOUS +# define ARENAS_USE_MMAP +# endif #endif +/* Forward declaration */ +static void* _PyObject_Malloc(void *ctx, size_t size); +static void _PyObject_Free(void *ctx, void *p); +static void* _PyObject_Realloc(void *ctx, void *ptr, size_t size); +#endif + + +static void * +_PyMem_RawMalloc(void *ctx, size_t size) +{ + /* PyMem_Malloc(0) means malloc(1). Some systems would return NULL + for malloc(0), which would be treated as an error. Some platforms would + return a pointer with no memory behind it, which would break pymalloc. + To solve these problems, allocate an extra byte. */ + if (size == 0) + size = 1; + return malloc(size); +} + +static void * +_PyMem_RawRealloc(void *ctx, void *ptr, size_t size) +{ + if (size == 0) + size = 1; + return realloc(ptr, size); +} + +static void +_PyMem_RawFree(void *ctx, void *ptr) +{ + free(ptr); +} + + #ifdef MS_WINDOWS -#include +static void * +_PyObject_ArenaVirtualAlloc(void *ctx, size_t size) +{ + return VirtualAlloc(NULL, size, + MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +} + +static void +_PyObject_ArenaVirtualFree(void *ctx, void *ptr, size_t size) +{ + VirtualFree(ptr, 0, MEM_RELEASE); +} + +#elif defined(ARENAS_USE_MMAP) +static void * +_PyObject_ArenaMmap(void *ctx, size_t size) +{ + void *ptr; + ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (ptr == MAP_FAILED) + return NULL; + assert(ptr != NULL); + return ptr; +} + +static void +_PyObject_ArenaMunmap(void *ctx, void *ptr, size_t size) +{ + munmap(ptr, size); +} + +#else +static void * +_PyObject_ArenaMalloc(void *ctx, size_t size) +{ + return malloc(size); +} + +static void +_PyObject_ArenaFree(void *ctx, void *ptr, size_t size) +{ + free(ptr); +} #endif + +#define PYRAW_FUNCS _PyMem_RawMalloc, _PyMem_RawRealloc, _PyMem_RawFree +#ifdef WITH_PYMALLOC +#define PYOBJECT_FUNCS _PyObject_Malloc, _PyObject_Realloc, _PyObject_Free +#else +#define PYOBJECT_FUNCS PYRAW_FUNCS +#endif + +#ifdef PYMALLOC_DEBUG +typedef struct { + /* We tag each block with an API ID in order to tag API violations */ + char api_id; + PyMemAllocator alloc; +} debug_alloc_api_t; +static struct { + debug_alloc_api_t raw; + debug_alloc_api_t mem; + debug_alloc_api_t obj; +} _PyMem_Debug = { + {'r', {NULL, PYRAW_FUNCS}}, + {'m', {NULL, PYRAW_FUNCS}}, + {'o', {NULL, PYOBJECT_FUNCS}} + }; + +#define PYDEBUG_FUNCS _PyMem_DebugMalloc, _PyMem_DebugRealloc, _PyMem_DebugFree +#endif + +static PyMemAllocator _PyMem_Raw = { +#ifdef PYMALLOC_DEBUG + &_PyMem_Debug.raw, PYDEBUG_FUNCS +#else + NULL, PYRAW_FUNCS +#endif + }; + +static PyMemAllocator _PyMem = { +#ifdef PYMALLOC_DEBUG + &_PyMem_Debug.mem, PYDEBUG_FUNCS +#else + NULL, PYRAW_FUNCS +#endif + }; + +static PyMemAllocator _PyObject = { +#ifdef PYMALLOC_DEBUG + &_PyMem_Debug.obj, PYDEBUG_FUNCS +#else + NULL, PYOBJECT_FUNCS +#endif + }; + +#undef PYRAW_FUNCS +#undef PYOBJECT_FUNCS +#undef PYDEBUG_FUNCS + +static PyObjectArenaAllocator _PyObject_Arena = {NULL, +#ifdef MS_WINDOWS + _PyObject_ArenaVirtualAlloc, _PyObject_ArenaVirtualFree +#elif defined(ARENAS_USE_MMAP) + _PyObject_ArenaMmap, _PyObject_ArenaMunmap +#else + _PyObject_ArenaMalloc, _PyObject_ArenaFree +#endif + }; + +void +PyMem_SetupDebugHooks(void) +{ +#ifdef PYMALLOC_DEBUG + PyMemAllocator alloc; + + alloc.malloc = _PyMem_DebugMalloc; + alloc.realloc = _PyMem_DebugRealloc; + alloc.free = _PyMem_DebugFree; + + if (_PyMem_Raw.malloc != _PyMem_DebugMalloc) { + alloc.ctx = &_PyMem_Debug.raw; + PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &_PyMem_Debug.raw.alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); + } + + if (_PyMem.malloc != _PyMem_DebugMalloc) { + alloc.ctx = &_PyMem_Debug.mem; + PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &_PyMem_Debug.mem.alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); + } + + if (_PyObject.malloc != _PyMem_DebugMalloc) { + alloc.ctx = &_PyMem_Debug.obj; + PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &_PyMem_Debug.obj.alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); + } +#endif +} + +void +PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator) +{ + switch(domain) + { + case PYMEM_DOMAIN_RAW: *allocator = _PyMem_Raw; break; + case PYMEM_DOMAIN_MEM: *allocator = _PyMem; break; + case PYMEM_DOMAIN_OBJ: *allocator = _PyObject; break; + default: + /* unknown domain */ + allocator->ctx = NULL; + allocator->malloc = NULL; + allocator->realloc = NULL; + allocator->free = NULL; + } +} + +void +PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator) +{ + switch(domain) + { + case PYMEM_DOMAIN_RAW: _PyMem_Raw = *allocator; break; + case PYMEM_DOMAIN_MEM: _PyMem = *allocator; break; + case PYMEM_DOMAIN_OBJ: _PyObject = *allocator; break; + /* ignore unknown domain */ + } + +} + +void +PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator) +{ + *allocator = _PyObject_Arena; +} + +void +PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator) +{ + _PyObject_Arena = *allocator; +} + +void * +PyMem_RawMalloc(size_t size) +{ + /* + * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes. + * Most python internals blindly use a signed Py_ssize_t to track + * things without checking for overflows or negatives. + * As size_t is unsigned, checking for size < 0 is not required. + */ + if (size > (size_t)PY_SSIZE_T_MAX) + return NULL; + + return _PyMem_Raw.malloc(_PyMem_Raw.ctx, size); +} + +void* +PyMem_RawRealloc(void *ptr, size_t new_size) +{ + /* see PyMem_RawMalloc() */ + if (new_size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyMem_Raw.realloc(_PyMem_Raw.ctx, ptr, new_size); +} + +void PyMem_RawFree(void *ptr) +{ + _PyMem_Raw.free(_PyMem_Raw.ctx, ptr); +} + +void * +PyMem_Malloc(size_t size) +{ + /* see PyMem_RawMalloc() */ + if (size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyMem.malloc(_PyMem.ctx, size); +} + +void * +PyMem_Realloc(void *ptr, size_t new_size) +{ + /* see PyMem_RawMalloc() */ + if (new_size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyMem.realloc(_PyMem.ctx, ptr, new_size); +} + +void +PyMem_Free(void *ptr) +{ + _PyMem.free(_PyMem.ctx, ptr); +} + +void * +PyObject_Malloc(size_t size) +{ + /* see PyMem_RawMalloc() */ + if (size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyObject.malloc(_PyObject.ctx, size); +} + +void * +PyObject_Realloc(void *ptr, size_t new_size) +{ + /* see PyMem_RawMalloc() */ + if (new_size > (size_t)PY_SSIZE_T_MAX) + return NULL; + return _PyObject.realloc(_PyObject.ctx, ptr, new_size); +} + +void +PyObject_Free(void *ptr) +{ + _PyObject.free(_PyObject.ctx, ptr); +} + + +#ifdef WITH_PYMALLOC + #ifdef WITH_VALGRIND #include @@ -549,7 +857,6 @@ struct arena_object* arenaobj; uint excess; /* number of bytes above pool alignment */ void *address; - int err; #ifdef PYMALLOC_DEBUG if (Py_GETENV("PYTHONMALLOCSTATS")) @@ -571,7 +878,7 @@ return NULL; /* overflow */ #endif nbytes = numarenas * sizeof(*arenas); - arenaobj = (struct arena_object *)realloc(arenas, nbytes); + arenaobj = (struct arena_object *)PyMem_Realloc(arenas, nbytes); if (arenaobj == NULL) return NULL; arenas = arenaobj; @@ -602,19 +909,8 @@ arenaobj = unused_arena_objects; unused_arena_objects = arenaobj->nextarena; assert(arenaobj->address == 0); -#ifdef MS_WINDOWS - address = (void*)VirtualAlloc(NULL, ARENA_SIZE, - MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - err = (address == NULL); -#elif defined(ARENAS_USE_MMAP) - address = mmap(NULL, ARENA_SIZE, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - err = (address == MAP_FAILED); -#else - address = malloc(ARENA_SIZE); - err = (address == 0); -#endif - if (err) { + address = _PyObject_Arena.alloc(_PyObject_Arena.ctx, ARENA_SIZE); + if (address == NULL) { /* The allocation failed: return NULL after putting the * arenaobj back. */ @@ -777,9 +1073,8 @@ * Unless the optimizer reorders everything, being too smart... */ -#undef PyObject_Malloc -void * -PyObject_Malloc(size_t nbytes) +static void * +_PyObject_Malloc(void *ctx, size_t nbytes) { block *bp; poolp pool; @@ -796,17 +1091,6 @@ #endif /* - * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes. - * Most python internals blindly use a signed Py_ssize_t to track - * things without checking for overflows or negatives. - * As size_t is unsigned, checking for nbytes < 0 is not required. - */ - if (nbytes > PY_SSIZE_T_MAX) { - _Py_AllocatedBlocks--; - return NULL; - } - - /* * This implicitly redirects malloc(0). */ if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) { @@ -978,10 +1262,8 @@ * last chance to serve the request) or when the max memory limit * has been reached. */ - if (nbytes == 0) - nbytes = 1; { - void *result = malloc(nbytes); + void *result = PyMem_Malloc(nbytes); if (!result) _Py_AllocatedBlocks--; return result; @@ -990,9 +1272,8 @@ /* free */ -#undef PyObject_Free -void -PyObject_Free(void *p) +static void +_PyObject_Free(void *ctx, void *p) { poolp pool; block *lastfree; @@ -1101,13 +1382,8 @@ unused_arena_objects = ao; /* Free the entire arena. */ -#ifdef MS_WINDOWS - VirtualFree((void *)ao->address, 0, MEM_RELEASE); -#elif defined(ARENAS_USE_MMAP) - munmap((void *)ao->address, ARENA_SIZE); -#else - free((void *)ao->address); -#endif + _PyObject_Arena.free(_PyObject_Arena.ctx, + (void *)ao->address, ARENA_SIZE); ao->address = 0; /* mark unassociated */ --narenas_currently_allocated; @@ -1216,7 +1492,7 @@ redirect: #endif /* We didn't allocate this address. */ - free(p); + PyMem_Free(p); } /* realloc. If p is NULL, this acts like malloc(nbytes). Else if nbytes==0, @@ -1224,9 +1500,8 @@ * return a non-NULL result. */ -#undef PyObject_Realloc -void * -PyObject_Realloc(void *p, size_t nbytes) +static void * +_PyObject_Realloc(void *ctx, void *p, size_t nbytes) { void *bp; poolp pool; @@ -1236,16 +1511,7 @@ #endif if (p == NULL) - return PyObject_Malloc(nbytes); - - /* - * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes. - * Most python internals blindly use a signed Py_ssize_t to track - * things without checking for overflows or negatives. - * As size_t is unsigned, checking for nbytes < 0 is not required. - */ - if (nbytes > PY_SSIZE_T_MAX) - return NULL; + return _PyObject_Malloc(ctx, nbytes); #ifdef WITH_VALGRIND /* Treat running_on_valgrind == -1 the same as 0 */ @@ -1273,10 +1539,10 @@ } size = nbytes; } - bp = PyObject_Malloc(nbytes); + bp = _PyObject_Malloc(ctx, nbytes); if (bp != NULL) { memcpy(bp, p, size); - PyObject_Free(p); + _PyObject_Free(ctx, p); } return bp; } @@ -1294,14 +1560,14 @@ * at p. Instead we punt: let C continue to manage this block. */ if (nbytes) - return realloc(p, nbytes); + return PyMem_Realloc(p, nbytes); /* C doesn't define the result of realloc(p, 0) (it may or may not * return NULL then), but Python's docs promise that nbytes==0 never * returns NULL. We don't pass 0 to realloc(), to avoid that endcase * to begin with. Even then, we can't be sure that realloc() won't * return NULL. */ - bp = realloc(p, 1); + bp = PyMem_Realloc(p, 1); return bp ? bp : p; } @@ -1311,24 +1577,6 @@ /* pymalloc not enabled: Redirect the entry points to malloc. These will * only be used by extensions that are compiled with pymalloc enabled. */ -void * -PyObject_Malloc(size_t n) -{ - return PyMem_MALLOC(n); -} - -void * -PyObject_Realloc(void *p, size_t n) -{ - return PyMem_REALLOC(p, n); -} - -void -PyObject_Free(void *p) -{ - PyMem_FREE(p); -} - Py_ssize_t _Py_GetAllocatedBlocks(void) { @@ -1354,10 +1602,6 @@ #define DEADBYTE 0xDB /* dead (newly freed) memory */ #define FORBIDDENBYTE 0xFB /* untouchable bytes at each end of a block */ -/* We tag each block with an API ID in order to tag API violations */ -#define _PYMALLOC_MEM_ID 'm' /* the PyMem_Malloc() API */ -#define _PYMALLOC_OBJ_ID 'o' /* The PyObject_Malloc() API */ - static size_t serialno = 0; /* incremented on each debug {m,re}alloc */ /* serialno is always incremented via calling this routine. The point is @@ -1440,58 +1684,18 @@ p[2*S+n: 2*S+n+S] Copies of FORBIDDENBYTE. Used to catch over- writes and reads. p[2*S+n+S: 2*S+n+2*S] - A serial number, incremented by 1 on each call to _PyObject_DebugMalloc - and _PyObject_DebugRealloc. + A serial number, incremented by 1 on each call to _PyMem_DebugMalloc + and _PyMem_DebugRealloc. This is a big-endian size_t. If "bad memory" is detected later, the serial number gives an excellent way to set a breakpoint on the next run, to capture the instant at which this block was passed out. */ -/* debug replacements for the PyMem_* memory API */ -void * -_PyMem_DebugMalloc(size_t nbytes) +static void * +_PyMem_DebugMalloc(void *ctx, size_t nbytes) { - return _PyObject_DebugMallocApi(_PYMALLOC_MEM_ID, nbytes); -} -void * -_PyMem_DebugRealloc(void *p, size_t nbytes) -{ - return _PyObject_DebugReallocApi(_PYMALLOC_MEM_ID, p, nbytes); -} -void -_PyMem_DebugFree(void *p) -{ - _PyObject_DebugFreeApi(_PYMALLOC_MEM_ID, p); -} - -/* debug replacements for the PyObject_* memory API */ -void * -_PyObject_DebugMalloc(size_t nbytes) -{ - return _PyObject_DebugMallocApi(_PYMALLOC_OBJ_ID, nbytes); -} -void * -_PyObject_DebugRealloc(void *p, size_t nbytes) -{ - return _PyObject_DebugReallocApi(_PYMALLOC_OBJ_ID, p, nbytes); -} -void -_PyObject_DebugFree(void *p) -{ - _PyObject_DebugFreeApi(_PYMALLOC_OBJ_ID, p); -} -void -_PyObject_DebugCheckAddress(const void *p) -{ - _PyObject_DebugCheckAddressApi(_PYMALLOC_OBJ_ID, p); -} - - -/* generic debug memory api, with an "id" to identify the API in use */ -void * -_PyObject_DebugMallocApi(char id, size_t nbytes) -{ + debug_alloc_api_t *api = (debug_alloc_api_t *)ctx; uchar *p; /* base address of malloc'ed block */ uchar *tail; /* p + 2*SST + nbytes == pointer to tail pad bytes */ size_t total; /* nbytes + 4*SST */ @@ -1502,14 +1706,14 @@ /* overflow: can't represent total as a size_t */ return NULL; - p = (uchar *)PyObject_Malloc(total); + p = (uchar *)api->alloc.malloc(api->alloc.ctx, total); if (p == NULL) return NULL; /* at p, write size (SST bytes), id (1 byte), pad (SST-1 bytes) */ write_size_t(p, nbytes); - p[SST] = (uchar)id; - memset(p + SST + 1 , FORBIDDENBYTE, SST-1); + p[SST] = (uchar)api->api_id; + memset(p + SST + 1, FORBIDDENBYTE, SST-1); if (nbytes > 0) memset(p + 2*SST, CLEANBYTE, nbytes); @@ -1527,25 +1731,27 @@ Then fills the original bytes with DEADBYTE. Then calls the underlying free. */ -void -_PyObject_DebugFreeApi(char api, void *p) +static void +_PyMem_DebugFree(void *ctx, void *p) { + debug_alloc_api_t *api = (debug_alloc_api_t *)ctx; uchar *q = (uchar *)p - 2*SST; /* address returned from malloc */ size_t nbytes; if (p == NULL) return; - _PyObject_DebugCheckAddressApi(api, p); + _PyMem_DebugCheckAddress(api->api_id, p); nbytes = read_size_t(q); nbytes += 4*SST; if (nbytes > 0) memset(q, DEADBYTE, nbytes); - PyObject_Free(q); + api->alloc.free(api->alloc.ctx, q); } -void * -_PyObject_DebugReallocApi(char api, void *p, size_t nbytes) +static void * +_PyMem_DebugRealloc(void *ctx, void *p, size_t nbytes) { + debug_alloc_api_t *api = (debug_alloc_api_t *)ctx; uchar *q = (uchar *)p; uchar *tail; size_t total; /* nbytes + 4*SST */ @@ -1553,9 +1759,9 @@ int i; if (p == NULL) - return _PyObject_DebugMallocApi(api, nbytes); + return _PyMem_DebugMalloc(ctx, nbytes); - _PyObject_DebugCheckAddressApi(api, p); + _PyMem_DebugCheckAddress(api->api_id, p); bumpserialno(); original_nbytes = read_size_t(q - 2*SST); total = nbytes + 4*SST; @@ -1572,12 +1778,12 @@ * case we didn't get the chance to mark the old memory with DEADBYTE, * but we live with that. */ - q = (uchar *)PyObject_Realloc(q - 2*SST, total); + q = (uchar *)api->alloc.realloc(api->alloc.ctx, q - 2*SST, total); if (q == NULL) return NULL; write_size_t(q, nbytes); - assert(q[SST] == (uchar)api); + assert(q[SST] == (uchar)api->api_id); for (i = 1; i < SST; ++i) assert(q[SST + i] == FORBIDDENBYTE); q += 2*SST; @@ -1599,8 +1805,8 @@ * and call Py_FatalError to kill the program. * The API id, is also checked. */ - void -_PyObject_DebugCheckAddressApi(char api, const void *p) +static void +_PyMem_DebugCheckAddress(char api, const void *p) { const uchar *q = (const uchar *)p; char msgbuf[64]; @@ -1652,7 +1858,7 @@ } /* Display info to stderr about the memory block at p. */ -void +static void _PyObject_DebugDumpAddress(const void *p) { const uchar *q = (const uchar *)p; diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -243,7 +243,7 @@ $(OutDir)python_d.exe Console - 2100000 + 4194304 0x1d000000 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 09:28:16 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 7 Jul 2013 09:28:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Cleanup_of_doc?= =?utf-8?q?umentation_change_from_=2317860?= Message-ID: <3bp1c01hmbz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/f4747e1ce2b1 changeset: 84476:f4747e1ce2b1 branch: 3.3 parent: 84467:b8028f74bac4 user: Ronald Oussoren date: Sun Jul 07 09:26:45 2013 +0200 summary: Cleanup of documentation change from #17860 Reformulated the textual change, and applied it to the docstring as well. files: Doc/library/subprocess.rst | 11 +++++++---- Lib/subprocess.py | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -290,11 +290,14 @@ .. index:: single: universal newlines; subprocess module - If *universal_newlines* is ``True``, the file objects *stdin*, *stdout* and - *stderr* will be opened as text streams in :term:`universal newlines` mode + If *universal_newlines* is ``False`` the file objects *stdin*, *stdout* and + *stderr* will be opened as binary streams, and no line ending conversion is + done. + + If *universal_newlines* is ``True``, these file objects + will be opened as text streams in :term:`universal newlines` mode using the encoding returned by :func:`locale.getpreferredencoding(False) - `, otherwise these streams will be opened - as binary streams. For *stdin*, line ending characters + `. For *stdin*, line ending characters ``'\n'`` in the input will be converted to the default line separator :data:`os.linesep`. For *stdout* and *stderr*, all line endings in the output will be converted to ``'\n'``. For more information see the diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -104,6 +104,9 @@ If env is not None, it defines the environment variables for the new process. +If universal_newlines is false, the file objects stdin, stdout and stderr +are opened as binary files, and no line ending conversion is done. + If universal_newlines is true, the file objects stdout and stderr are opened as a text files, but lines may be terminated by any of '\n', the Unix end-of-line convention, '\r', the old Macintosh convention or -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 09:28:17 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 7 Jul 2013 09:28:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=283=2E3-=3Edefault=29_Cleanup_of_documentation_change_f?= =?utf-8?q?rom_=2317860?= Message-ID: <3bp1c13v4Hz7Lkn@mail.python.org> http://hg.python.org/cpython/rev/83810f67d16b changeset: 84477:83810f67d16b parent: 84475:cc0c8c1c9cca parent: 84476:f4747e1ce2b1 user: Ronald Oussoren date: Sun Jul 07 09:28:01 2013 +0200 summary: (3.3->default) Cleanup of documentation change from #17860 Reformulated the textual change, and applied it to the docstring as well. files: Doc/library/subprocess.rst | 11 +++++++---- Lib/subprocess.py | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -300,11 +300,14 @@ .. index:: single: universal newlines; subprocess module - If *universal_newlines* is ``True``, the file objects *stdin*, *stdout* and - *stderr* will be opened as text streams in :term:`universal newlines` mode + If *universal_newlines* is ``False`` the file objects *stdin*, *stdout* and + *stderr* will be opened as binary streams, and no line ending conversion is + done. + + If *universal_newlines* is ``True``, these file objects + will be opened as text streams in :term:`universal newlines` mode using the encoding returned by :func:`locale.getpreferredencoding(False) - `, otherwise these streams will be opened - as binary streams. For *stdin*, line ending characters + `. For *stdin*, line ending characters ``'\n'`` in the input will be converted to the default line separator :data:`os.linesep`. For *stdout* and *stderr*, all line endings in the output will be converted to ``'\n'``. For more information see the diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -104,6 +104,9 @@ If env is not None, it defines the environment variables for the new process. +If universal_newlines is false, the file objects stdin, stdout and stderr +are opened as binary files, and no line ending conversion is done. + If universal_newlines is true, the file objects stdout and stderr are opened as a text files, but lines may be terminated by any of '\n', the Unix end-of-line convention, '\r', the old Macintosh convention or -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 09:50:23 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 7 Jul 2013 09:50:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4Mzc3?= =?utf-8?q?=3A_Code_cleanup_in_Python_Launcher?= Message-ID: <3bp25W2N3nzQT2@mail.python.org> http://hg.python.org/cpython/rev/5d41ebc79738 changeset: 84478:5d41ebc79738 branch: 2.7 parent: 84457:7ec9255d4189 user: Ronald Oussoren date: Sun Jul 07 09:49:23 2013 +0200 summary: Issue #18377: Code cleanup in Python Launcher This changeset fixes a number of compiler warnings in the Python Launcher binary for OSX. It also cleans up whitespace usage in those sources. files: Mac/PythonLauncher/FileSettings.h | 5 - Mac/PythonLauncher/FileSettings.m | 46 ++--- Mac/PythonLauncher/MyAppDelegate.m | 6 +- Mac/PythonLauncher/MyDocument.m | 20 +- Mac/PythonLauncher/PreferencesWindowController.m | 23 +- Mac/PythonLauncher/doscript.h | 2 +- Mac/PythonLauncher/doscript.m | 78 +++++----- Mac/PythonLauncher/main.m | 4 +- 8 files changed, 83 insertions(+), 101 deletions(-) diff --git a/Mac/PythonLauncher/FileSettings.h b/Mac/PythonLauncher/FileSettings.h --- a/Mac/PythonLauncher/FileSettings.h +++ b/Mac/PythonLauncher/FileSettings.h @@ -45,18 +45,13 @@ + (id)getFactorySettingsForFileType: (NSString *)filetype; + (id)newSettingsForFileType: (NSString *)filetype; -//- (id)init; - (id)initForFileType: (NSString *)filetype; - (id)initForFSDefaultFileType: (NSString *)filetype; - (id)initForDefaultFileType: (NSString *)filetype; -//- (id)initWithFileSettings: (FileSettings *)source; - (void)updateFromSource: (id )source; - (NSString *)commandLineForScript: (NSString *)script; -//- (void)applyFactorySettingsForFileType: (NSString *)filetype; -//- (void)saveDefaults; -//- (void)applyUserDefaults: (NSString *)filetype; - (void)applyValuesFromDict: (NSDictionary *)dict; - (void)reset; - (NSArray *) interpreters; diff --git a/Mac/PythonLauncher/FileSettings.m b/Mac/PythonLauncher/FileSettings.m --- a/Mac/PythonLauncher/FileSettings.m +++ b/Mac/PythonLauncher/FileSettings.m @@ -14,7 +14,7 @@ { static FileSettings *fsdefault_py, *fsdefault_pyw, *fsdefault_pyc; FileSettings **curdefault; - + if ([filetype isEqualToString: @"Python Script"]) { curdefault = &fsdefault_py; } else if ([filetype isEqualToString: @"Python GUI Script"]) { @@ -36,7 +36,7 @@ { static FileSettings *default_py, *default_pyw, *default_pyc; FileSettings **curdefault; - + if ([filetype isEqualToString: @"Python Script"]) { curdefault = &default_py; } else if ([filetype isEqualToString: @"Python GUI Script"]) { @@ -57,7 +57,7 @@ + (id)newSettingsForFileType: (NSString *)filetype { FileSettings *cur; - + cur = [FileSettings new]; [cur initForFileType: filetype]; return [cur retain]; @@ -67,7 +67,7 @@ { self = [super init]; if (!self) return self; - + interpreter = [source->interpreter retain]; honourhashbang = source->honourhashbang; debug = source->debug; @@ -81,36 +81,30 @@ with_terminal = source->with_terminal; prefskey = source->prefskey; if (prefskey) [prefskey retain]; - + return self; } - (id)initForFileType: (NSString *)filetype { FileSettings *defaults; - + defaults = [FileSettings getDefaultsForFileType: filetype]; self = [self initWithFileSettings: defaults]; origsource = [defaults retain]; return self; } -//- (id)init -//{ -// self = [self initForFileType: @"Python Script"]; -// return self; -//} - - (id)initForFSDefaultFileType: (NSString *)filetype { int i; NSString *filename; NSDictionary *dict; static NSDictionary *factorySettings; - + self = [super init]; if (!self) return self; - + if (factorySettings == NULL) { NSBundle *bdl = [NSBundle mainBundle]; NSString *path = [ bdl pathForResource: @"factorySettings" @@ -149,18 +143,18 @@ { NSUserDefaults *defaults; NSDictionary *dict; - + defaults = [NSUserDefaults standardUserDefaults]; dict = [defaults dictionaryForKey: filetype]; if (!dict) return; [self applyValuesFromDict: dict]; } - + - (id)initForDefaultFileType: (NSString *)filetype { FileSettings *fsdefaults; - + fsdefaults = [FileSettings getFactorySettingsForFileType: filetype]; self = [self initWithFileSettings: fsdefaults]; if (!self) return self; @@ -220,7 +214,7 @@ - (void)applyValuesFromDict: (NSDictionary *)dict { id value; - + value = [dict objectForKey: @"interpreter"]; if (value) interpreter = [value retain]; value = [dict objectForKey: @"honourhashbang"]; @@ -247,12 +241,12 @@ - (NSString*)_replaceSingleQuotes: (NSString*)string { - /* Replace all single-quotes by '"'"', that way shellquoting will - * be correct when the result value is delimited using single quotes. - */ - NSArray* components = [string componentsSeparatedByString:@"'"]; + /* Replace all single-quotes by '"'"', that way shellquoting will + * be correct when the result value is delimited using single quotes. + */ + NSArray* components = [string componentsSeparatedByString:@"'"]; - return [components componentsJoinedByString:@"'\"'\"'"]; + return [components componentsJoinedByString:@"'\"'\"'"]; } - (NSString *)commandLineForScript: (NSString *)script @@ -265,7 +259,7 @@ script_dir = [script substringToIndex: [script length]-[[script lastPathComponent] length]]; - + if (honourhashbang && (fp=fopen([script fileSystemRepresentation], "r")) && fgets(hashbangbuf, sizeof(hashbangbuf), fp) && @@ -278,7 +272,7 @@ } if (!cur_interp) cur_interp = interpreter; - + return [NSString stringWithFormat: @"cd '%@' && '%@'%s%s%s%s%s%s %@ '%@' %@ %s", [self _replaceSingleQuotes:script_dir], @@ -297,7 +291,7 @@ - (NSArray *) interpreters { return interpreters;}; -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return interpreter;}; - (BOOL) honourhashbang { return honourhashbang; }; - (BOOL) debug { return debug;}; diff --git a/Mac/PythonLauncher/MyAppDelegate.m b/Mac/PythonLauncher/MyAppDelegate.m --- a/Mac/PythonLauncher/MyAppDelegate.m +++ b/Mac/PythonLauncher/MyAppDelegate.m @@ -33,7 +33,7 @@ - (BOOL)shouldShowUI { - // if this call comes before applicationDidFinishLaunching: we + // if this call comes before applicationDidFinishLaunching: we // should terminate immedeately after starting the script. if (!initial_action_done) should_terminate = YES; @@ -62,7 +62,7 @@ static NSString *extensions[] = { @"py", @"pyw", @"pyc", NULL}; NSString **ext_p; int i; - + if ([[NSUserDefaults standardUserDefaults] boolForKey: @"SkipFileBindingTest"]) return; ourUrl = [NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]]; @@ -92,5 +92,5 @@ } } } - + @end diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m --- a/Mac/PythonLauncher/MyDocument.m +++ b/Mac/PythonLauncher/MyDocument.m @@ -16,7 +16,7 @@ { self = [super init]; if (self) { - + // Add your subclass-specific initialization here. // If an error occurs here, send a [self dealloc] message and return nil. script = [@".py" retain]; @@ -37,20 +37,17 @@ { NSApplication *app = [NSApplication sharedApplication]; [super close]; - if ([[app delegate] shouldTerminate]) + if ([(MyAppDelegate*)[app delegate] shouldTerminate]) [app terminate: self]; } - (void)load_defaults { -// if (settings) [settings release]; settings = [FileSettings newSettingsForFileType: filetype]; } - (void)update_display { -// [[self window] setTitle: script]; - [interpreter setStringValue: [settings interpreter]]; [honourhashbang setState: [settings honourhashbang]]; [debug setState: [settings debug]]; @@ -62,7 +59,7 @@ [others setStringValue: [settings others]]; [scriptargs setStringValue: [settings scriptargs]]; [with_terminal setState: [settings with_terminal]]; - + [commandline setStringValue: [settings commandLineForScript: script]]; } @@ -75,7 +72,7 @@ { const char *cmdline; int sts; - + cmdline = [[settings commandLineForScript: script] UTF8String]; if ([settings with_terminal]) { sts = doscript(cmdline); @@ -107,14 +104,13 @@ { // Insert code here to read your document from the given data. You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead. BOOL show_ui; - - // ask the app delegate whether we should show the UI or not. - show_ui = [[[NSApplication sharedApplication] delegate] shouldShowUI]; + + // ask the app delegate whether we should show the UI or not. + show_ui = [(MyAppDelegate*)[[NSApplication sharedApplication] delegate] shouldShowUI]; [script release]; script = [fileName retain]; [filetype release]; filetype = [type retain]; -// if (settings) [settings release]; settings = [FileSettings newSettingsForFileType: filetype]; if (show_ui) { [self update_display]; @@ -152,7 +148,7 @@ [self update_display]; } -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return [interpreter stringValue];}; - (BOOL) honourhashbang { return [honourhashbang state];}; - (BOOL) debug { return [debug state];}; diff --git a/Mac/PythonLauncher/PreferencesWindowController.m b/Mac/PythonLauncher/PreferencesWindowController.m --- a/Mac/PythonLauncher/PreferencesWindowController.m +++ b/Mac/PythonLauncher/PreferencesWindowController.m @@ -5,7 +5,7 @@ + getPreferencesWindow { static PreferencesWindowController *_singleton; - + if (!_singleton) _singleton = [[PreferencesWindowController alloc] init]; [_singleton showWindow: _singleton]; @@ -21,15 +21,13 @@ - (void)load_defaults { NSString *title = [filetype titleOfSelectedItem]; - + settings = [FileSettings getDefaultsForFileType: title]; } - (void)update_display { -// [[self window] setTitle: script]; - - [interpreter reloadData]; + [interpreter reloadData]; [interpreter setStringValue: [settings interpreter]]; [honourhashbang setState: [settings honourhashbang]]; [debug setState: [settings debug]]; @@ -41,7 +39,6 @@ [others setStringValue: [settings others]]; [with_terminal setState: [settings with_terminal]]; // Not scriptargs, it isn't for preferences - [commandline setStringValue: [settings commandLineForScript: @""]]; } @@ -75,7 +72,7 @@ [self update_display]; } -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return [interpreter stringValue];}; - (BOOL) honourhashbang { return [honourhashbang state]; }; - (BOOL) debug { return [debug state];}; @@ -98,23 +95,23 @@ // NSComboBoxDataSource protocol - (unsigned int)comboBox:(NSComboBox *)aComboBox indexOfItemWithStringValue:(NSString *)aString { - NSArray *interp_list = [settings interpreters]; + NSArray *interp_list = [settings interpreters]; unsigned int rv = [interp_list indexOfObjectIdenticalTo: aString]; - return rv; + return rv; } - (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)index { - NSArray *interp_list = [settings interpreters]; + NSArray *interp_list = [settings interpreters]; id rv = [interp_list objectAtIndex: index]; - return rv; + return rv; } - (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox { - NSArray *interp_list = [settings interpreters]; + NSArray *interp_list = [settings interpreters]; int rv = [interp_list count]; - return rv; + return rv; } diff --git a/Mac/PythonLauncher/doscript.h b/Mac/PythonLauncher/doscript.h --- a/Mac/PythonLauncher/doscript.h +++ b/Mac/PythonLauncher/doscript.h @@ -9,4 +9,4 @@ #include -extern int doscript(const char *command); \ No newline at end of file +extern int doscript(const char *command); diff --git a/Mac/PythonLauncher/doscript.m b/Mac/PythonLauncher/doscript.m --- a/Mac/PythonLauncher/doscript.m +++ b/Mac/PythonLauncher/doscript.m @@ -11,49 +11,49 @@ #import #import "doscript.h" -extern int +extern int doscript(const char *command) { - char *bundleID = "com.apple.Terminal"; - AppleEvent evt, res; - AEDesc desc; - OSStatus err; + char *bundleID = "com.apple.Terminal"; + AppleEvent evt, res; + AEDesc desc; + OSStatus err; - [[NSWorkspace sharedWorkspace] launchApplication:@"/Applications/Utilities/Terminal.app/"]; + [[NSWorkspace sharedWorkspace] launchApplication:@"/Applications/Utilities/Terminal.app/"]; - // Build event - err = AEBuildAppleEvent(kAECoreSuite, kAEDoScript, - typeApplicationBundleID, - bundleID, strlen(bundleID), - kAutoGenerateReturnID, - kAnyTransactionID, - &evt, NULL, - "'----':utf8(@)", strlen(command), - command); - if (err) { - NSLog(@"AEBuildAppleEvent failed: %d\n", err); - return err; - } + // Build event + err = AEBuildAppleEvent(kAECoreSuite, kAEDoScript, + typeApplicationBundleID, + bundleID, strlen(bundleID), + kAutoGenerateReturnID, + kAnyTransactionID, + &evt, NULL, + "'----':utf8(@)", strlen(command), + command); + if (err) { + NSLog(@"AEBuildAppleEvent failed: %ld\n", (long)err); + return err; + } - // Send event and check for any Apple Event Manager errors - err = AESendMessage(&evt, &res, kAEWaitReply, kAEDefaultTimeout); - AEDisposeDesc(&evt); - if (err) { - NSLog(@"AESendMessage failed: %d\n", err); - return err; - } - // Check for any application errors - err = AEGetParamDesc(&res, keyErrorNumber, typeSInt32, &desc); - AEDisposeDesc(&res); - if (!err) { - AEGetDescData(&desc, &err, sizeof(err)); - NSLog(@"Terminal returned an error: %d", err); - AEDisposeDesc(&desc); - } else if (err == errAEDescNotFound) { - err = noErr; - } else { - NSLog(@"AEGetPArmDesc returned an error: %d", err); - } + // Send event and check for any Apple Event Manager errors + err = AESendMessage(&evt, &res, kAEWaitReply, kAEDefaultTimeout); + AEDisposeDesc(&evt); + if (err) { + NSLog(@"AESendMessage failed: %ld\n", (long)err); + return err; + } + // Check for any application errors + err = AEGetParamDesc(&res, keyErrorNumber, typeSInt32, &desc); + AEDisposeDesc(&res); + if (!err) { + AEGetDescData(&desc, &err, sizeof(err)); + NSLog(@"Terminal returned an error: %ld", (long)err); + AEDisposeDesc(&desc); + } else if (err == errAEDescNotFound) { + err = noErr; + } else { + NSLog(@"AEGetPArmDesc returned an error: %ld", (long)err); + } - return err; + return err; } diff --git a/Mac/PythonLauncher/main.m b/Mac/PythonLauncher/main.m --- a/Mac/PythonLauncher/main.m +++ b/Mac/PythonLauncher/main.m @@ -11,7 +11,7 @@ int main(int argc, const char *argv[]) { - char *home = getenv("HOME"); - if (home) chdir(home); + char *home = getenv("HOME"); + if (home) chdir(home); return NSApplicationMain(argc, argv); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 09:54:24 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 7 Jul 2013 09:54:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4Mzc3?= =?utf-8?q?=3A_Code_cleanup_in_Python_Launcher?= Message-ID: <3bp2B8137Lz7LjX@mail.python.org> http://hg.python.org/cpython/rev/738cba2bf849 changeset: 84479:738cba2bf849 branch: 3.3 parent: 84476:f4747e1ce2b1 user: Ronald Oussoren date: Sun Jul 07 09:53:08 2013 +0200 summary: Issue #18377: Code cleanup in Python Launcher This changeset fixes a number of compiler warnings in the Python Launcher binary for OSX. It also cleans up whitespace usage in those sources. files: Mac/PythonLauncher/FileSettings.h | 5 - Mac/PythonLauncher/FileSettings.m | 46 ++--- Mac/PythonLauncher/MyAppDelegate.m | 6 +- Mac/PythonLauncher/MyDocument.m | 20 +- Mac/PythonLauncher/PreferencesWindowController.m | 11 +- Mac/PythonLauncher/doscript.h | 2 +- Mac/PythonLauncher/doscript.m | 78 +++++----- Mac/PythonLauncher/main.m | 4 +- 8 files changed, 77 insertions(+), 95 deletions(-) diff --git a/Mac/PythonLauncher/FileSettings.h b/Mac/PythonLauncher/FileSettings.h --- a/Mac/PythonLauncher/FileSettings.h +++ b/Mac/PythonLauncher/FileSettings.h @@ -45,18 +45,13 @@ + (id)getFactorySettingsForFileType: (NSString *)filetype; + (id)newSettingsForFileType: (NSString *)filetype; -//- (id)init; - (id)initForFileType: (NSString *)filetype; - (id)initForFSDefaultFileType: (NSString *)filetype; - (id)initForDefaultFileType: (NSString *)filetype; -//- (id)initWithFileSettings: (FileSettings *)source; - (void)updateFromSource: (id )source; - (NSString *)commandLineForScript: (NSString *)script; -//- (void)applyFactorySettingsForFileType: (NSString *)filetype; -//- (void)saveDefaults; -//- (void)applyUserDefaults: (NSString *)filetype; - (void)applyValuesFromDict: (NSDictionary *)dict; - (void)reset; - (NSArray *) interpreters; diff --git a/Mac/PythonLauncher/FileSettings.m b/Mac/PythonLauncher/FileSettings.m --- a/Mac/PythonLauncher/FileSettings.m +++ b/Mac/PythonLauncher/FileSettings.m @@ -14,7 +14,7 @@ { static FileSettings *fsdefault_py, *fsdefault_pyw, *fsdefault_pyc; FileSettings **curdefault; - + if ([filetype isEqualToString: @"Python Script"]) { curdefault = &fsdefault_py; } else if ([filetype isEqualToString: @"Python GUI Script"]) { @@ -36,7 +36,7 @@ { static FileSettings *default_py, *default_pyw, *default_pyc; FileSettings **curdefault; - + if ([filetype isEqualToString: @"Python Script"]) { curdefault = &default_py; } else if ([filetype isEqualToString: @"Python GUI Script"]) { @@ -57,7 +57,7 @@ + (id)newSettingsForFileType: (NSString *)filetype { FileSettings *cur; - + cur = [FileSettings new]; [cur initForFileType: filetype]; return [cur retain]; @@ -67,7 +67,7 @@ { self = [super init]; if (!self) return self; - + interpreter = [source->interpreter retain]; honourhashbang = source->honourhashbang; debug = source->debug; @@ -81,36 +81,30 @@ with_terminal = source->with_terminal; prefskey = source->prefskey; if (prefskey) [prefskey retain]; - + return self; } - (id)initForFileType: (NSString *)filetype { FileSettings *defaults; - + defaults = [FileSettings getDefaultsForFileType: filetype]; self = [self initWithFileSettings: defaults]; origsource = [defaults retain]; return self; } -//- (id)init -//{ -// self = [self initForFileType: @"Python Script"]; -// return self; -//} - - (id)initForFSDefaultFileType: (NSString *)filetype { int i; NSString *filename; NSDictionary *dict; static NSDictionary *factorySettings; - + self = [super init]; if (!self) return self; - + if (factorySettings == NULL) { NSBundle *bdl = [NSBundle mainBundle]; NSString *path = [ bdl pathForResource: @"factorySettings" @@ -149,18 +143,18 @@ { NSUserDefaults *defaults; NSDictionary *dict; - + defaults = [NSUserDefaults standardUserDefaults]; dict = [defaults dictionaryForKey: filetype]; if (!dict) return; [self applyValuesFromDict: dict]; } - + - (id)initForDefaultFileType: (NSString *)filetype { FileSettings *fsdefaults; - + fsdefaults = [FileSettings getFactorySettingsForFileType: filetype]; self = [self initWithFileSettings: fsdefaults]; if (!self) return self; @@ -220,7 +214,7 @@ - (void)applyValuesFromDict: (NSDictionary *)dict { id value; - + value = [dict objectForKey: @"interpreter"]; if (value) interpreter = [value retain]; value = [dict objectForKey: @"honourhashbang"]; @@ -247,12 +241,12 @@ - (NSString*)_replaceSingleQuotes: (NSString*)string { - /* Replace all single-quotes by '"'"', that way shellquoting will - * be correct when the result value is delimited using single quotes. - */ - NSArray* components = [string componentsSeparatedByString:@"'"]; + /* Replace all single-quotes by '"'"', that way shellquoting will + * be correct when the result value is delimited using single quotes. + */ + NSArray* components = [string componentsSeparatedByString:@"'"]; - return [components componentsJoinedByString:@"'\"'\"'"]; + return [components componentsJoinedByString:@"'\"'\"'"]; } - (NSString *)commandLineForScript: (NSString *)script @@ -265,7 +259,7 @@ script_dir = [script substringToIndex: [script length]-[[script lastPathComponent] length]]; - + if (honourhashbang && (fp=fopen([script fileSystemRepresentation], "r")) && fgets(hashbangbuf, sizeof(hashbangbuf), fp) && @@ -278,7 +272,7 @@ } if (!cur_interp) cur_interp = interpreter; - + return [NSString stringWithFormat: @"cd '%@' && '%@'%s%s%s%s%s%s %@ '%@' %@ %s", [self _replaceSingleQuotes:script_dir], @@ -297,7 +291,7 @@ - (NSArray *) interpreters { return interpreters;}; -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return interpreter;}; - (BOOL) honourhashbang { return honourhashbang; }; - (BOOL) debug { return debug;}; diff --git a/Mac/PythonLauncher/MyAppDelegate.m b/Mac/PythonLauncher/MyAppDelegate.m --- a/Mac/PythonLauncher/MyAppDelegate.m +++ b/Mac/PythonLauncher/MyAppDelegate.m @@ -33,7 +33,7 @@ - (BOOL)shouldShowUI { - // if this call comes before applicationDidFinishLaunching: we + // if this call comes before applicationDidFinishLaunching: we // should terminate immedeately after starting the script. if (!initial_action_done) should_terminate = YES; @@ -62,7 +62,7 @@ static NSString *extensions[] = { @"py", @"pyw", @"pyc", NULL}; NSString **ext_p; int i; - + if ([[NSUserDefaults standardUserDefaults] boolForKey: @"SkipFileBindingTest"]) return; ourUrl = [NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]]; @@ -92,5 +92,5 @@ } } } - + @end diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m --- a/Mac/PythonLauncher/MyDocument.m +++ b/Mac/PythonLauncher/MyDocument.m @@ -16,7 +16,7 @@ { self = [super init]; if (self) { - + // Add your subclass-specific initialization here. // If an error occurs here, send a [self dealloc] message and return nil. script = [@".py" retain]; @@ -37,20 +37,17 @@ { NSApplication *app = [NSApplication sharedApplication]; [super close]; - if ([[app delegate] shouldTerminate]) + if ([(MyAppDelegate*)[app delegate] shouldTerminate]) [app terminate: self]; } - (void)load_defaults { -// if (settings) [settings release]; settings = [FileSettings newSettingsForFileType: filetype]; } - (void)update_display { -// [[self window] setTitle: script]; - [interpreter setStringValue: [settings interpreter]]; [honourhashbang setState: [settings honourhashbang]]; [debug setState: [settings debug]]; @@ -62,7 +59,7 @@ [others setStringValue: [settings others]]; [scriptargs setStringValue: [settings scriptargs]]; [with_terminal setState: [settings with_terminal]]; - + [commandline setStringValue: [settings commandLineForScript: script]]; } @@ -75,7 +72,7 @@ { const char *cmdline; int sts; - + cmdline = [[settings commandLineForScript: script] UTF8String]; if ([settings with_terminal]) { sts = doscript(cmdline); @@ -107,14 +104,13 @@ { // Insert code here to read your document from the given data. You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead. BOOL show_ui; - - // ask the app delegate whether we should show the UI or not. - show_ui = [[[NSApplication sharedApplication] delegate] shouldShowUI]; + + // ask the app delegate whether we should show the UI or not. + show_ui = [(MyAppDelegate*)[[NSApplication sharedApplication] delegate] shouldShowUI]; [script release]; script = [fileName retain]; [filetype release]; filetype = [type retain]; -// if (settings) [settings release]; settings = [FileSettings newSettingsForFileType: filetype]; if (show_ui) { [self update_display]; @@ -152,7 +148,7 @@ [self update_display]; } -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return [interpreter stringValue];}; - (BOOL) honourhashbang { return [honourhashbang state];}; - (BOOL) debug { return [debug state];}; diff --git a/Mac/PythonLauncher/PreferencesWindowController.m b/Mac/PythonLauncher/PreferencesWindowController.m --- a/Mac/PythonLauncher/PreferencesWindowController.m +++ b/Mac/PythonLauncher/PreferencesWindowController.m @@ -5,7 +5,7 @@ + getPreferencesWindow { static PreferencesWindowController *_singleton; - + if (!_singleton) _singleton = [[PreferencesWindowController alloc] init]; [_singleton showWindow: _singleton]; @@ -21,15 +21,13 @@ - (void)load_defaults { NSString *title = [filetype titleOfSelectedItem]; - + settings = [FileSettings getDefaultsForFileType: title]; } - (void)update_display { -// [[self window] setTitle: script]; - - [interpreter reloadData]; + [interpreter reloadData]; [interpreter setStringValue: [settings interpreter]]; [honourhashbang setState: [settings honourhashbang]]; [debug setState: [settings debug]]; @@ -41,7 +39,6 @@ [others setStringValue: [settings others]]; [with_terminal setState: [settings with_terminal]]; // Not scriptargs, it isn't for preferences - [commandline setStringValue: [settings commandLineForScript: @""]]; } @@ -75,7 +72,7 @@ [self update_display]; } -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return [interpreter stringValue];}; - (BOOL) honourhashbang { return [honourhashbang state]; }; - (BOOL) debug { return [debug state];}; diff --git a/Mac/PythonLauncher/doscript.h b/Mac/PythonLauncher/doscript.h --- a/Mac/PythonLauncher/doscript.h +++ b/Mac/PythonLauncher/doscript.h @@ -9,4 +9,4 @@ #include -extern int doscript(const char *command); \ No newline at end of file +extern int doscript(const char *command); diff --git a/Mac/PythonLauncher/doscript.m b/Mac/PythonLauncher/doscript.m --- a/Mac/PythonLauncher/doscript.m +++ b/Mac/PythonLauncher/doscript.m @@ -11,49 +11,49 @@ #import #import "doscript.h" -extern int +extern int doscript(const char *command) { - char *bundleID = "com.apple.Terminal"; - AppleEvent evt, res; - AEDesc desc; - OSStatus err; + char *bundleID = "com.apple.Terminal"; + AppleEvent evt, res; + AEDesc desc; + OSStatus err; - [[NSWorkspace sharedWorkspace] launchApplication:@"/Applications/Utilities/Terminal.app/"]; + [[NSWorkspace sharedWorkspace] launchApplication:@"/Applications/Utilities/Terminal.app/"]; - // Build event - err = AEBuildAppleEvent(kAECoreSuite, kAEDoScript, - typeApplicationBundleID, - bundleID, strlen(bundleID), - kAutoGenerateReturnID, - kAnyTransactionID, - &evt, NULL, - "'----':utf8(@)", strlen(command), - command); - if (err) { - NSLog(@"AEBuildAppleEvent failed: %d\n", err); - return err; - } + // Build event + err = AEBuildAppleEvent(kAECoreSuite, kAEDoScript, + typeApplicationBundleID, + bundleID, strlen(bundleID), + kAutoGenerateReturnID, + kAnyTransactionID, + &evt, NULL, + "'----':utf8(@)", strlen(command), + command); + if (err) { + NSLog(@"AEBuildAppleEvent failed: %ld\n", (long)err); + return err; + } - // Send event and check for any Apple Event Manager errors - err = AESendMessage(&evt, &res, kAEWaitReply, kAEDefaultTimeout); - AEDisposeDesc(&evt); - if (err) { - NSLog(@"AESendMessage failed: %d\n", err); - return err; - } - // Check for any application errors - err = AEGetParamDesc(&res, keyErrorNumber, typeSInt32, &desc); - AEDisposeDesc(&res); - if (!err) { - AEGetDescData(&desc, &err, sizeof(err)); - NSLog(@"Terminal returned an error: %d", err); - AEDisposeDesc(&desc); - } else if (err == errAEDescNotFound) { - err = noErr; - } else { - NSLog(@"AEGetPArmDesc returned an error: %d", err); - } + // Send event and check for any Apple Event Manager errors + err = AESendMessage(&evt, &res, kAEWaitReply, kAEDefaultTimeout); + AEDisposeDesc(&evt); + if (err) { + NSLog(@"AESendMessage failed: %ld\n", (long)err); + return err; + } + // Check for any application errors + err = AEGetParamDesc(&res, keyErrorNumber, typeSInt32, &desc); + AEDisposeDesc(&res); + if (!err) { + AEGetDescData(&desc, &err, sizeof(err)); + NSLog(@"Terminal returned an error: %ld", (long)err); + AEDisposeDesc(&desc); + } else if (err == errAEDescNotFound) { + err = noErr; + } else { + NSLog(@"AEGetPArmDesc returned an error: %ld", (long)err); + } - return err; + return err; } diff --git a/Mac/PythonLauncher/main.m b/Mac/PythonLauncher/main.m --- a/Mac/PythonLauncher/main.m +++ b/Mac/PythonLauncher/main.m @@ -11,7 +11,7 @@ int main(int argc, const char *argv[]) { - char *home = getenv("HOME"); - if (home) chdir(home); + char *home = getenv("HOME"); + if (home) chdir(home); return NSApplicationMain(argc, argv); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 09:54:25 2013 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 7 Jul 2013 09:54:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=283=2E3-=3Edefault=29_Issue_=2318377=3A_Code_cleanup_in?= =?utf-8?q?_Python_Launcher?= Message-ID: <3bp2B94TFbz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/d7a59e6f48df changeset: 84480:d7a59e6f48df parent: 84477:83810f67d16b parent: 84479:738cba2bf849 user: Ronald Oussoren date: Sun Jul 07 09:54:08 2013 +0200 summary: (3.3->default) Issue #18377: Code cleanup in Python Launcher This changeset fixes a number of compiler warnings in the Python Launcher binary for OSX. It also cleans up whitespace usage in those sources. files: Mac/PythonLauncher/FileSettings.h | 5 - Mac/PythonLauncher/FileSettings.m | 46 ++--- Mac/PythonLauncher/MyAppDelegate.m | 6 +- Mac/PythonLauncher/MyDocument.m | 20 +- Mac/PythonLauncher/PreferencesWindowController.m | 11 +- Mac/PythonLauncher/doscript.h | 2 +- Mac/PythonLauncher/doscript.m | 78 +++++----- Mac/PythonLauncher/main.m | 4 +- 8 files changed, 77 insertions(+), 95 deletions(-) diff --git a/Mac/PythonLauncher/FileSettings.h b/Mac/PythonLauncher/FileSettings.h --- a/Mac/PythonLauncher/FileSettings.h +++ b/Mac/PythonLauncher/FileSettings.h @@ -45,18 +45,13 @@ + (id)getFactorySettingsForFileType: (NSString *)filetype; + (id)newSettingsForFileType: (NSString *)filetype; -//- (id)init; - (id)initForFileType: (NSString *)filetype; - (id)initForFSDefaultFileType: (NSString *)filetype; - (id)initForDefaultFileType: (NSString *)filetype; -//- (id)initWithFileSettings: (FileSettings *)source; - (void)updateFromSource: (id )source; - (NSString *)commandLineForScript: (NSString *)script; -//- (void)applyFactorySettingsForFileType: (NSString *)filetype; -//- (void)saveDefaults; -//- (void)applyUserDefaults: (NSString *)filetype; - (void)applyValuesFromDict: (NSDictionary *)dict; - (void)reset; - (NSArray *) interpreters; diff --git a/Mac/PythonLauncher/FileSettings.m b/Mac/PythonLauncher/FileSettings.m --- a/Mac/PythonLauncher/FileSettings.m +++ b/Mac/PythonLauncher/FileSettings.m @@ -14,7 +14,7 @@ { static FileSettings *fsdefault_py, *fsdefault_pyw, *fsdefault_pyc; FileSettings **curdefault; - + if ([filetype isEqualToString: @"Python Script"]) { curdefault = &fsdefault_py; } else if ([filetype isEqualToString: @"Python GUI Script"]) { @@ -36,7 +36,7 @@ { static FileSettings *default_py, *default_pyw, *default_pyc; FileSettings **curdefault; - + if ([filetype isEqualToString: @"Python Script"]) { curdefault = &default_py; } else if ([filetype isEqualToString: @"Python GUI Script"]) { @@ -57,7 +57,7 @@ + (id)newSettingsForFileType: (NSString *)filetype { FileSettings *cur; - + cur = [FileSettings new]; [cur initForFileType: filetype]; return [cur retain]; @@ -67,7 +67,7 @@ { self = [super init]; if (!self) return self; - + interpreter = [source->interpreter retain]; honourhashbang = source->honourhashbang; debug = source->debug; @@ -81,36 +81,30 @@ with_terminal = source->with_terminal; prefskey = source->prefskey; if (prefskey) [prefskey retain]; - + return self; } - (id)initForFileType: (NSString *)filetype { FileSettings *defaults; - + defaults = [FileSettings getDefaultsForFileType: filetype]; self = [self initWithFileSettings: defaults]; origsource = [defaults retain]; return self; } -//- (id)init -//{ -// self = [self initForFileType: @"Python Script"]; -// return self; -//} - - (id)initForFSDefaultFileType: (NSString *)filetype { int i; NSString *filename; NSDictionary *dict; static NSDictionary *factorySettings; - + self = [super init]; if (!self) return self; - + if (factorySettings == NULL) { NSBundle *bdl = [NSBundle mainBundle]; NSString *path = [ bdl pathForResource: @"factorySettings" @@ -149,18 +143,18 @@ { NSUserDefaults *defaults; NSDictionary *dict; - + defaults = [NSUserDefaults standardUserDefaults]; dict = [defaults dictionaryForKey: filetype]; if (!dict) return; [self applyValuesFromDict: dict]; } - + - (id)initForDefaultFileType: (NSString *)filetype { FileSettings *fsdefaults; - + fsdefaults = [FileSettings getFactorySettingsForFileType: filetype]; self = [self initWithFileSettings: fsdefaults]; if (!self) return self; @@ -220,7 +214,7 @@ - (void)applyValuesFromDict: (NSDictionary *)dict { id value; - + value = [dict objectForKey: @"interpreter"]; if (value) interpreter = [value retain]; value = [dict objectForKey: @"honourhashbang"]; @@ -247,12 +241,12 @@ - (NSString*)_replaceSingleQuotes: (NSString*)string { - /* Replace all single-quotes by '"'"', that way shellquoting will - * be correct when the result value is delimited using single quotes. - */ - NSArray* components = [string componentsSeparatedByString:@"'"]; + /* Replace all single-quotes by '"'"', that way shellquoting will + * be correct when the result value is delimited using single quotes. + */ + NSArray* components = [string componentsSeparatedByString:@"'"]; - return [components componentsJoinedByString:@"'\"'\"'"]; + return [components componentsJoinedByString:@"'\"'\"'"]; } - (NSString *)commandLineForScript: (NSString *)script @@ -265,7 +259,7 @@ script_dir = [script substringToIndex: [script length]-[[script lastPathComponent] length]]; - + if (honourhashbang && (fp=fopen([script fileSystemRepresentation], "r")) && fgets(hashbangbuf, sizeof(hashbangbuf), fp) && @@ -278,7 +272,7 @@ } if (!cur_interp) cur_interp = interpreter; - + return [NSString stringWithFormat: @"cd '%@' && '%@'%s%s%s%s%s%s %@ '%@' %@ %s", [self _replaceSingleQuotes:script_dir], @@ -297,7 +291,7 @@ - (NSArray *) interpreters { return interpreters;}; -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return interpreter;}; - (BOOL) honourhashbang { return honourhashbang; }; - (BOOL) debug { return debug;}; diff --git a/Mac/PythonLauncher/MyAppDelegate.m b/Mac/PythonLauncher/MyAppDelegate.m --- a/Mac/PythonLauncher/MyAppDelegate.m +++ b/Mac/PythonLauncher/MyAppDelegate.m @@ -33,7 +33,7 @@ - (BOOL)shouldShowUI { - // if this call comes before applicationDidFinishLaunching: we + // if this call comes before applicationDidFinishLaunching: we // should terminate immedeately after starting the script. if (!initial_action_done) should_terminate = YES; @@ -62,7 +62,7 @@ static NSString *extensions[] = { @"py", @"pyw", @"pyc", NULL}; NSString **ext_p; int i; - + if ([[NSUserDefaults standardUserDefaults] boolForKey: @"SkipFileBindingTest"]) return; ourUrl = [NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]]; @@ -92,5 +92,5 @@ } } } - + @end diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m --- a/Mac/PythonLauncher/MyDocument.m +++ b/Mac/PythonLauncher/MyDocument.m @@ -16,7 +16,7 @@ { self = [super init]; if (self) { - + // Add your subclass-specific initialization here. // If an error occurs here, send a [self dealloc] message and return nil. script = [@".py" retain]; @@ -37,20 +37,17 @@ { NSApplication *app = [NSApplication sharedApplication]; [super close]; - if ([[app delegate] shouldTerminate]) + if ([(MyAppDelegate*)[app delegate] shouldTerminate]) [app terminate: self]; } - (void)load_defaults { -// if (settings) [settings release]; settings = [FileSettings newSettingsForFileType: filetype]; } - (void)update_display { -// [[self window] setTitle: script]; - [interpreter setStringValue: [settings interpreter]]; [honourhashbang setState: [settings honourhashbang]]; [debug setState: [settings debug]]; @@ -62,7 +59,7 @@ [others setStringValue: [settings others]]; [scriptargs setStringValue: [settings scriptargs]]; [with_terminal setState: [settings with_terminal]]; - + [commandline setStringValue: [settings commandLineForScript: script]]; } @@ -75,7 +72,7 @@ { const char *cmdline; int sts; - + cmdline = [[settings commandLineForScript: script] UTF8String]; if ([settings with_terminal]) { sts = doscript(cmdline); @@ -107,14 +104,13 @@ { // Insert code here to read your document from the given data. You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead. BOOL show_ui; - - // ask the app delegate whether we should show the UI or not. - show_ui = [[[NSApplication sharedApplication] delegate] shouldShowUI]; + + // ask the app delegate whether we should show the UI or not. + show_ui = [(MyAppDelegate*)[[NSApplication sharedApplication] delegate] shouldShowUI]; [script release]; script = [fileName retain]; [filetype release]; filetype = [type retain]; -// if (settings) [settings release]; settings = [FileSettings newSettingsForFileType: filetype]; if (show_ui) { [self update_display]; @@ -152,7 +148,7 @@ [self update_display]; } -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return [interpreter stringValue];}; - (BOOL) honourhashbang { return [honourhashbang state];}; - (BOOL) debug { return [debug state];}; diff --git a/Mac/PythonLauncher/PreferencesWindowController.m b/Mac/PythonLauncher/PreferencesWindowController.m --- a/Mac/PythonLauncher/PreferencesWindowController.m +++ b/Mac/PythonLauncher/PreferencesWindowController.m @@ -5,7 +5,7 @@ + getPreferencesWindow { static PreferencesWindowController *_singleton; - + if (!_singleton) _singleton = [[PreferencesWindowController alloc] init]; [_singleton showWindow: _singleton]; @@ -21,15 +21,13 @@ - (void)load_defaults { NSString *title = [filetype titleOfSelectedItem]; - + settings = [FileSettings getDefaultsForFileType: title]; } - (void)update_display { -// [[self window] setTitle: script]; - - [interpreter reloadData]; + [interpreter reloadData]; [interpreter setStringValue: [settings interpreter]]; [honourhashbang setState: [settings honourhashbang]]; [debug setState: [settings debug]]; @@ -41,7 +39,6 @@ [others setStringValue: [settings others]]; [with_terminal setState: [settings with_terminal]]; // Not scriptargs, it isn't for preferences - [commandline setStringValue: [settings commandLineForScript: @""]]; } @@ -75,7 +72,7 @@ [self update_display]; } -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return [interpreter stringValue];}; - (BOOL) honourhashbang { return [honourhashbang state]; }; - (BOOL) debug { return [debug state];}; diff --git a/Mac/PythonLauncher/doscript.h b/Mac/PythonLauncher/doscript.h --- a/Mac/PythonLauncher/doscript.h +++ b/Mac/PythonLauncher/doscript.h @@ -9,4 +9,4 @@ #include -extern int doscript(const char *command); \ No newline at end of file +extern int doscript(const char *command); diff --git a/Mac/PythonLauncher/doscript.m b/Mac/PythonLauncher/doscript.m --- a/Mac/PythonLauncher/doscript.m +++ b/Mac/PythonLauncher/doscript.m @@ -11,49 +11,49 @@ #import #import "doscript.h" -extern int +extern int doscript(const char *command) { - char *bundleID = "com.apple.Terminal"; - AppleEvent evt, res; - AEDesc desc; - OSStatus err; + char *bundleID = "com.apple.Terminal"; + AppleEvent evt, res; + AEDesc desc; + OSStatus err; - [[NSWorkspace sharedWorkspace] launchApplication:@"/Applications/Utilities/Terminal.app/"]; + [[NSWorkspace sharedWorkspace] launchApplication:@"/Applications/Utilities/Terminal.app/"]; - // Build event - err = AEBuildAppleEvent(kAECoreSuite, kAEDoScript, - typeApplicationBundleID, - bundleID, strlen(bundleID), - kAutoGenerateReturnID, - kAnyTransactionID, - &evt, NULL, - "'----':utf8(@)", strlen(command), - command); - if (err) { - NSLog(@"AEBuildAppleEvent failed: %d\n", err); - return err; - } + // Build event + err = AEBuildAppleEvent(kAECoreSuite, kAEDoScript, + typeApplicationBundleID, + bundleID, strlen(bundleID), + kAutoGenerateReturnID, + kAnyTransactionID, + &evt, NULL, + "'----':utf8(@)", strlen(command), + command); + if (err) { + NSLog(@"AEBuildAppleEvent failed: %ld\n", (long)err); + return err; + } - // Send event and check for any Apple Event Manager errors - err = AESendMessage(&evt, &res, kAEWaitReply, kAEDefaultTimeout); - AEDisposeDesc(&evt); - if (err) { - NSLog(@"AESendMessage failed: %d\n", err); - return err; - } - // Check for any application errors - err = AEGetParamDesc(&res, keyErrorNumber, typeSInt32, &desc); - AEDisposeDesc(&res); - if (!err) { - AEGetDescData(&desc, &err, sizeof(err)); - NSLog(@"Terminal returned an error: %d", err); - AEDisposeDesc(&desc); - } else if (err == errAEDescNotFound) { - err = noErr; - } else { - NSLog(@"AEGetPArmDesc returned an error: %d", err); - } + // Send event and check for any Apple Event Manager errors + err = AESendMessage(&evt, &res, kAEWaitReply, kAEDefaultTimeout); + AEDisposeDesc(&evt); + if (err) { + NSLog(@"AESendMessage failed: %ld\n", (long)err); + return err; + } + // Check for any application errors + err = AEGetParamDesc(&res, keyErrorNumber, typeSInt32, &desc); + AEDisposeDesc(&res); + if (!err) { + AEGetDescData(&desc, &err, sizeof(err)); + NSLog(@"Terminal returned an error: %ld", (long)err); + AEDisposeDesc(&desc); + } else if (err == errAEDescNotFound) { + err = noErr; + } else { + NSLog(@"AEGetPArmDesc returned an error: %ld", (long)err); + } - return err; + return err; } diff --git a/Mac/PythonLauncher/main.m b/Mac/PythonLauncher/main.m --- a/Mac/PythonLauncher/main.m +++ b/Mac/PythonLauncher/main.m @@ -11,7 +11,7 @@ int main(int argc, const char *argv[]) { - char *home = getenv("HOME"); - if (home) chdir(home); + char *home = getenv("HOME"); + if (home) chdir(home); return NSApplicationMain(argc, argv); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 11:11:37 2013 From: python-checkins at python.org (ezio.melotti) Date: Sun, 7 Jul 2013 11:11:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2318020=3A_improve_html?= =?utf-8?q?=2Eescape_speed_by_an_order_of_magnitude=2E__Patch_by_Matt?= Message-ID: <3bp3vF07Nsz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/db5f2b74e369 changeset: 84481:db5f2b74e369 user: Ezio Melotti date: Sun Jul 07 11:11:24 2013 +0200 summary: #18020: improve html.escape speed by an order of magnitude. Patch by Matt Bryant. files: Lib/html/__init__.py | 13 ++++++------- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/html/__init__.py b/Lib/html/__init__.py --- a/Lib/html/__init__.py +++ b/Lib/html/__init__.py @@ -2,11 +2,6 @@ General functions for HTML manipulation. """ - -_escape_map = {ord('&'): '&', ord('<'): '<', ord('>'): '>'} -_escape_map_full = {ord('&'): '&', ord('<'): '<', ord('>'): '>', - ord('"'): '"', ord('\''): '''} - # NB: this is a candidate for a bytes/string polymorphic interface def escape(s, quote=True): @@ -16,6 +11,10 @@ characters, both double quote (") and single quote (') characters are also translated. """ + s = s.replace("&", "&") # Must be done first! + s = s.replace("<", "<") + s = s.replace(">", ">") if quote: - return s.translate(_escape_map_full) - return s.translate(_escape_map) + s = s.replace('"', """) + s = s.replace('\'', "'") + return s diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -172,6 +172,7 @@ Francisco Mart?n Brugu? Ian Bruntlett Floris Bruynooghe +Matt Bryant Stan Bubrouski Erik de Bueger Jan-Hein B?hrman diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -142,6 +142,9 @@ Library ------- +- Issue #18020: improve html.escape speed by an order of magnitude. + Patch by Matt Bryant. + - Issue #18347: ElementTree's html serializer now preserves the case of closing tags. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 12:47:12 2013 From: python-checkins at python.org (florent.xicluna) Date: Sun, 7 Jul 2013 12:47:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDEz?= =?utf-8?q?=3A_Fix_cgi=2EFieldStorage_to_parse_the_W3C_sample_form=2E?= Message-ID: <3bp61X2mRrzSqb@mail.python.org> http://hg.python.org/cpython/rev/406ce103c170 changeset: 84482:406ce103c170 branch: 3.3 parent: 84479:738cba2bf849 user: Florent Xicluna date: Sun Jul 07 12:44:28 2013 +0200 summary: Issue #18013: Fix cgi.FieldStorage to parse the W3C sample form. files: Lib/cgi.py | 2 +- Lib/test/test_cgi.py | 46 ++++++++++++++++++++++++++++++++ Misc/NEWS | 2 + 3 files changed, 49 insertions(+), 1 deletions(-) diff --git a/Lib/cgi.py b/Lib/cgi.py --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -699,7 +699,7 @@ self.encoding, self.errors) self.bytes_read += part.bytes_read self.list.append(part) - if self.bytes_read >= self.length: + if part.done or self.bytes_read >= self.length > 0: break self.skip_lines() diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -279,6 +279,27 @@ check('x' * (maxline - 1) + '\r') check('x' * (maxline - 1) + '\r' + 'y' * (maxline - 1)) + def test_fieldstorage_multipart_w3c(self): + # Test basic FieldStorage multipart parsing (W3C sample) + env = { + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY_W3), + 'CONTENT_LENGTH': str(len(POSTDATA_W3))} + fp = BytesIO(POSTDATA_W3.encode('latin-1')) + fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1") + self.assertEqual(len(fs.list), 2) + self.assertEqual(fs.list[0].name, 'submit-name') + self.assertEqual(fs.list[0].value, 'Larry') + self.assertEqual(fs.list[1].name, 'files') + files = fs.list[1].value + self.assertEqual(len(files), 2) + expect = [{'name': None, 'filename': 'file1.txt', 'value': b'... contents of file1.txt ...'}, + {'name': None, 'filename': 'file2.gif', 'value': b'...contents of file2.gif...'}] + for x in range(len(files)): + for k, exp in expect[x].items(): + got = getattr(files[x], k) + self.assertEqual(got, exp) + _qs_result = { 'key1': 'value1', 'key2': ['value2x', 'value2y'], @@ -428,6 +449,31 @@ -----------------------------721837373350705526688164684 """ +# http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4 +BOUNDARY_W3 = "AaB03x" +POSTDATA_W3 = """--AaB03x +Content-Disposition: form-data; name="submit-name" + +Larry +--AaB03x +Content-Disposition: form-data; name="files" +Content-Type: multipart/mixed; boundary=BbC04y + +--BbC04y +Content-Disposition: file; filename="file1.txt" +Content-Type: text/plain + +... contents of file1.txt ... +--BbC04y +Content-Disposition: file; filename="file2.gif" +Content-Type: image/gif +Content-Transfer-Encoding: binary + +...contents of file2.gif... +--BbC04y-- +--AaB03x-- +""" + def test_main(): run_unittest(CgiTests) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -41,6 +41,8 @@ Library ------- +- Issue #18013: Fix cgi.FieldStorage to parse the W3C sample form. + - Issue #18347: ElementTree's html serializer now preserves the case of closing tags. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 12:47:13 2013 From: python-checkins at python.org (florent.xicluna) Date: Sun, 7 Jul 2013 12:47:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2318013=3A_Fix_cgi=2EFieldStorage_to_parse_the_W3?= =?utf-8?q?C_sample_form=2E?= Message-ID: <3bp61Y57Ldz7LjN@mail.python.org> http://hg.python.org/cpython/rev/2ab2a2bfea49 changeset: 84483:2ab2a2bfea49 parent: 84481:db5f2b74e369 parent: 84482:406ce103c170 user: Florent Xicluna date: Sun Jul 07 12:46:28 2013 +0200 summary: Merge #18013: Fix cgi.FieldStorage to parse the W3C sample form. files: Lib/cgi.py | 2 +- Lib/test/test_cgi.py | 46 ++++++++++++++++++++++++++++++++ Misc/NEWS | 2 + 3 files changed, 49 insertions(+), 1 deletions(-) diff --git a/Lib/cgi.py b/Lib/cgi.py --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -699,7 +699,7 @@ self.encoding, self.errors) self.bytes_read += part.bytes_read self.list.append(part) - if self.bytes_read >= self.length: + if part.done or self.bytes_read >= self.length > 0: break self.skip_lines() diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -279,6 +279,27 @@ check('x' * (maxline - 1) + '\r') check('x' * (maxline - 1) + '\r' + 'y' * (maxline - 1)) + def test_fieldstorage_multipart_w3c(self): + # Test basic FieldStorage multipart parsing (W3C sample) + env = { + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY_W3), + 'CONTENT_LENGTH': str(len(POSTDATA_W3))} + fp = BytesIO(POSTDATA_W3.encode('latin-1')) + fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1") + self.assertEqual(len(fs.list), 2) + self.assertEqual(fs.list[0].name, 'submit-name') + self.assertEqual(fs.list[0].value, 'Larry') + self.assertEqual(fs.list[1].name, 'files') + files = fs.list[1].value + self.assertEqual(len(files), 2) + expect = [{'name': None, 'filename': 'file1.txt', 'value': b'... contents of file1.txt ...'}, + {'name': None, 'filename': 'file2.gif', 'value': b'...contents of file2.gif...'}] + for x in range(len(files)): + for k, exp in expect[x].items(): + got = getattr(files[x], k) + self.assertEqual(got, exp) + _qs_result = { 'key1': 'value1', 'key2': ['value2x', 'value2y'], @@ -428,6 +449,31 @@ -----------------------------721837373350705526688164684 """ +# http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4 +BOUNDARY_W3 = "AaB03x" +POSTDATA_W3 = """--AaB03x +Content-Disposition: form-data; name="submit-name" + +Larry +--AaB03x +Content-Disposition: form-data; name="files" +Content-Type: multipart/mixed; boundary=BbC04y + +--BbC04y +Content-Disposition: file; filename="file1.txt" +Content-Type: text/plain + +... contents of file1.txt ... +--BbC04y +Content-Disposition: file; filename="file2.gif" +Content-Type: image/gif +Content-Transfer-Encoding: binary + +...contents of file2.gif... +--BbC04y-- +--AaB03x-- +""" + def test_main(): run_unittest(CgiTests) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -142,6 +142,8 @@ Library ------- +- Issue #18013: Fix cgi.FieldStorage to parse the W3C sample form. + - Issue #18020: improve html.escape speed by an order of magnitude. Patch by Matt Bryant. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 13:16:16 2013 From: python-checkins at python.org (ezio.melotti) Date: Sun, 7 Jul 2013 13:16:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3MTk4OiBGaXgg?= =?utf-8?q?a_NameError_in_the_dbm_module=2E__Patch_by_Valentina_Mukhamedzh?= =?utf-8?q?anova=2E?= Message-ID: <3bp6g423Qbz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/65fce1dad331 changeset: 84484:65fce1dad331 branch: 3.3 parent: 84482:406ce103c170 user: Ezio Melotti date: Sun Jul 07 13:15:08 2013 +0200 summary: #17198: Fix a NameError in the dbm module. Patch by Valentina Mukhamedzhanova. files: Lib/dbm/__init__.py | 5 +++++ Lib/test/test_dbm.py | 18 ++++++++++++++++-- Misc/NEWS | 3 +++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -44,6 +44,11 @@ error = (error, IOError) +try: + from dbm import ndbm +except ImportError: + ndbm = None + def open(file, flag='r', mode=0o666): """Open or create database at path given by *file*. diff --git a/Lib/test/test_dbm.py b/Lib/test/test_dbm.py --- a/Lib/test/test_dbm.py +++ b/Lib/test/test_dbm.py @@ -9,6 +9,11 @@ # Skip tests if dbm module doesn't exist. dbm = test.support.import_module('dbm') +try: + from dbm import ndbm +except ImportError: + ndbm = None + _fname = test.support.TESTFN # @@ -130,7 +135,7 @@ delete_files() f = module.open(_fname, 'c') f.close() - self.assertEqual(name, dbm.whichdb(_fname)) + self.assertEqual(name, self.dbm.whichdb(_fname)) # Now add a key f = module.open(_fname, 'w') f[b"1"] = b"1" @@ -139,7 +144,15 @@ # and read it self.assertTrue(f[b"1"] == b"1") f.close() - self.assertEqual(name, dbm.whichdb(_fname)) + self.assertEqual(name, self.dbm.whichdb(_fname)) + + @unittest.skipUnless(ndbm, reason='Test requires ndbm') + def test_whichdb_ndbm(self): + # Issue 17198: check that ndbm which is referenced in whichdb is defined + db_file = '{}_ndbm.db'.format(_fname) + with open(db_file, 'w'): + self.addCleanup(test.support.unlink, db_file) + self.assertIsNone(self.dbm.whichdb(db_file[:-3])) def tearDown(self): delete_files() @@ -149,6 +162,7 @@ self.filename = test.support.TESTFN self.d = dbm.open(self.filename, 'c') self.d.close() + self.dbm = test.support.import_fresh_module('dbm') def test_keys(self): self.d = dbm.open(self.filename, 'c') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -41,6 +41,9 @@ Library ------- +- Issue #17198: Fix a NameError in the dbm module. Patch by Valentina + Mukhamedzhanova. + - Issue #18013: Fix cgi.FieldStorage to parse the W3C sample form. - Issue #18347: ElementTree's html serializer now preserves the case of -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 13:16:17 2013 From: python-checkins at python.org (ezio.melotti) Date: Sun, 7 Jul 2013 13:16:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE3MTk4OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3bp6g54Klpz7Ljp@mail.python.org> http://hg.python.org/cpython/rev/e91e9b9ba180 changeset: 84485:e91e9b9ba180 parent: 84483:2ab2a2bfea49 parent: 84484:65fce1dad331 user: Ezio Melotti date: Sun Jul 07 13:16:05 2013 +0200 summary: #17198: merge with 3.3. files: Lib/dbm/__init__.py | 5 +++++ Lib/test/test_dbm.py | 18 ++++++++++++++++-- Misc/NEWS | 3 +++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py --- a/Lib/dbm/__init__.py +++ b/Lib/dbm/__init__.py @@ -44,6 +44,11 @@ error = (error, OSError) +try: + from dbm import ndbm +except ImportError: + ndbm = None + def open(file, flag='r', mode=0o666): """Open or create database at path given by *file*. diff --git a/Lib/test/test_dbm.py b/Lib/test/test_dbm.py --- a/Lib/test/test_dbm.py +++ b/Lib/test/test_dbm.py @@ -9,6 +9,11 @@ # Skip tests if dbm module doesn't exist. dbm = test.support.import_module('dbm') +try: + from dbm import ndbm +except ImportError: + ndbm = None + _fname = test.support.TESTFN # @@ -130,7 +135,7 @@ delete_files() f = module.open(_fname, 'c') f.close() - self.assertEqual(name, dbm.whichdb(_fname)) + self.assertEqual(name, self.dbm.whichdb(_fname)) # Now add a key f = module.open(_fname, 'w') f[b"1"] = b"1" @@ -139,7 +144,15 @@ # and read it self.assertTrue(f[b"1"] == b"1") f.close() - self.assertEqual(name, dbm.whichdb(_fname)) + self.assertEqual(name, self.dbm.whichdb(_fname)) + + @unittest.skipUnless(ndbm, reason='Test requires ndbm') + def test_whichdb_ndbm(self): + # Issue 17198: check that ndbm which is referenced in whichdb is defined + db_file = '{}_ndbm.db'.format(_fname) + with open(db_file, 'w'): + self.addCleanup(test.support.unlink, db_file) + self.assertIsNone(self.dbm.whichdb(db_file[:-3])) def tearDown(self): delete_files() @@ -149,6 +162,7 @@ self.filename = test.support.TESTFN self.d = dbm.open(self.filename, 'c') self.d.close() + self.dbm = test.support.import_fresh_module('dbm') def test_keys(self): self.d = dbm.open(self.filename, 'c') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -142,6 +142,9 @@ Library ------- +- Issue #17198: Fix a NameError in the dbm module. Patch by Valentina + Mukhamedzhanova. + - Issue #18013: Fix cgi.FieldStorage to parse the W3C sample form. - Issue #18020: improve html.escape speed by an order of magnitude. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 13:37:32 2013 From: python-checkins at python.org (ezio.melotti) Date: Sun, 7 Jul 2013 13:37:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2318106=3A_refactor_tests?= =?utf-8?q?_to_use_subtests_and_proper_assert_methods=2E__Patch_by?= Message-ID: <3bp77c2lbdz7LjS@mail.python.org> http://hg.python.org/cpython/rev/a5010de76eda changeset: 84486:a5010de76eda user: Ezio Melotti date: Sun Jul 07 13:37:20 2013 +0200 summary: #18106: refactor tests to use subtests and proper assert methods. Patch by Vajrasky Kok. files: Lib/test/test_collections.py | 77 +++++++++++++---------- 1 files changed, 42 insertions(+), 35 deletions(-) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -918,23 +918,26 @@ words = Counter('which witch had which witches wrist watch'.split()) update_test = Counter() update_test.update(words) - for i, dup in enumerate([ - words.copy(), - copy.copy(words), - copy.deepcopy(words), - pickle.loads(pickle.dumps(words, 0)), - pickle.loads(pickle.dumps(words, 1)), - pickle.loads(pickle.dumps(words, 2)), - pickle.loads(pickle.dumps(words, -1)), - eval(repr(words)), - update_test, - Counter(words), - ]): - msg = (i, dup, words) - self.assertTrue(dup is not words) - self.assertEqual(dup, words) - self.assertEqual(len(dup), len(words)) - self.assertEqual(type(dup), type(words)) + for label, dup in [ + ('words.copy()', words.copy()), + ('copy.copy(words)', copy.copy(words)), + ('copy.deepcopy(words)', copy.deepcopy(words)), + ('pickle.loads(pickle.dumps(words, 0))', + pickle.loads(pickle.dumps(words, 0))), + ('pickle.loads(pickle.dumps(words, 1))', + pickle.loads(pickle.dumps(words, 1))), + ('pickle.loads(pickle.dumps(words, 2))', + pickle.loads(pickle.dumps(words, 2))), + ('pickle.loads(pickle.dumps(words, -1))', + pickle.loads(pickle.dumps(words, -1))), + ('eval(repr(words))', eval(repr(words))), + ('update_test', update_test), + ('Counter(words)', Counter(words)), + ]: + with self.subTest(label=label): + msg = "\ncopy: %s\nwords: %s" % (dup, words) + self.assertIsNot(dup, words, msg) + self.assertEqual(dup, words) def test_copy_subclass(self): class MyCounter(Counter): @@ -1213,24 +1216,28 @@ od = OrderedDict(pairs) update_test = OrderedDict() update_test.update(od) - for i, dup in enumerate([ - od.copy(), - copy.copy(od), - copy.deepcopy(od), - pickle.loads(pickle.dumps(od, 0)), - pickle.loads(pickle.dumps(od, 1)), - pickle.loads(pickle.dumps(od, 2)), - pickle.loads(pickle.dumps(od, 3)), - pickle.loads(pickle.dumps(od, -1)), - eval(repr(od)), - update_test, - OrderedDict(od), - ]): - self.assertTrue(dup is not od) - self.assertEqual(dup, od) - self.assertEqual(list(dup.items()), list(od.items())) - self.assertEqual(len(dup), len(od)) - self.assertEqual(type(dup), type(od)) + for label, dup in [ + ('od.copy()', od.copy()), + ('copy.copy(od)', copy.copy(od)), + ('copy.deepcopy(od)', copy.deepcopy(od)), + ('pickle.loads(pickle.dumps(od, 0))', + pickle.loads(pickle.dumps(od, 0))), + ('pickle.loads(pickle.dumps(od, 1))', + pickle.loads(pickle.dumps(od, 1))), + ('pickle.loads(pickle.dumps(od, 2))', + pickle.loads(pickle.dumps(od, 2))), + ('pickle.loads(pickle.dumps(od, 3))', + pickle.loads(pickle.dumps(od, 3))), + ('pickle.loads(pickle.dumps(od, -1))', + pickle.loads(pickle.dumps(od, -1))), + ('eval(repr(od))', eval(repr(od))), + ('update_test', update_test), + ('OrderedDict(od)', OrderedDict(od)), + ]: + with self.subTest(label=label): + msg = "\ncopy: %s\nod: %s" % (dup, od) + self.assertIsNot(dup, od, msg) + self.assertEqual(dup, od) def test_yaml_linkage(self): # Verify that __reduce__ is setup in a way that supports PyYAML's dump() feature. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 13:43:55 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 7 Jul 2013 13:43:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Use_macros_for_marking_and?= =?utf-8?q?_checking_endpoints_in_the_doubly-linked_list_of?= Message-ID: <3bp7Gz2KYWz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/ae9ee46bd471 changeset: 84487:ae9ee46bd471 user: Raymond Hettinger date: Sun Jul 07 01:43:42 2013 -1000 summary: Use macros for marking and checking endpoints in the doubly-linked list of blocks. * Add comment explaining the endpoint checks * Only do the checks in a debug build * Simplify newblock() to only require a length argument and leave the link updates to the calling code. * Also add comment for the freelisting logic. files: Modules/_collectionsmodule.c | 128 ++++++++++++++-------- 1 files changed, 81 insertions(+), 47 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -18,16 +18,14 @@ #define CENTER ((BLOCKLEN - 1) / 2) /* A `dequeobject` is composed of a doubly-linked list of `block` nodes. - * This list is not circular (the leftmost block has leftlink==NULL, - * and the rightmost block has rightlink==NULL). A deque d's first - * element is at d.leftblock[leftindex] and its last element is at - * d.rightblock[rightindex]; note that, unlike as for Python slice - * indices, these indices are inclusive on both ends. By being inclusive - * on both ends, algorithms for left and right operations become - * symmetrical which simplifies the design. + * The list of blocks is never empty, so d.leftblock and d.rightblock + * are never equal to NULL. The list is not circular. * - * The list of blocks is never empty, so d.leftblock and d.rightblock - * are never equal to NULL. + * A deque d's first element is at d.leftblock[leftindex] + * and its last element is at d.rightblock[rightindex]. + * Unlike Python slice indices, these indices are inclusive + * on both ends. This makes the algorithms for left and + * right operations more symmetrical and simplifies the design. * * The indices, d.leftindex and d.rightindex are always in the range * 0 <= index < BLOCKLEN. @@ -52,12 +50,38 @@ struct BLOCK *rightlink; } block; +/* For debug builds, add error checking to track the endpoints + * in the chain of links. The goal is to make sure that link + * assignments only take place at endpoints so that links already + * in use do not get overwritten. + * + * CHECK_END should happen before each assignment to a block's link field. + * MARK_END should happen whenever a link field becomes a new endpoint. + * This happens when new blocks are added or whenever an existing + * block is freed leaving another existing block as the new endpoint. + */ + +#if Py_DEBUG +#define MARK_END(link) link = NULL; +#define CHECK_END(link) assert(link == NULL); +#define CHECK_NOT_END(link) assert(link != NULL); +#else +#define MARK_END(link) +#define CHECK_END(link) +#define CHECK_NOT_END(link) +#endif + +/* A simple freelisting scheme is used to minimize calls to the memory + allocator. It accomodates common use cases where new blocks are being + added at about the same rate as old blocks are being freed. + */ + #define MAXFREEBLOCKS 10 static Py_ssize_t numfreeblocks = 0; static block *freeblocks[MAXFREEBLOCKS]; static block * -newblock(block *leftlink, block *rightlink, Py_ssize_t len) { +newblock(Py_ssize_t len) { block *b; /* To prevent len from overflowing PY_SSIZE_T_MAX, we refuse to * allocate new blocks if the current len is nearing overflow. */ @@ -68,17 +92,14 @@ } if (numfreeblocks) { numfreeblocks--; - b = freeblocks[numfreeblocks]; - } else { - b = PyMem_Malloc(sizeof(block)); - if (b == NULL) { - PyErr_NoMemory(); - return NULL; - } + return freeblocks[numfreeblocks]; } - b->leftlink = leftlink; - b->rightlink = rightlink; - return b; + b = PyMem_Malloc(sizeof(block)); + if (b != NULL) { + return b; + } + PyErr_NoMemory(); + return NULL; } static void @@ -132,11 +153,13 @@ if (deque == NULL) return NULL; - b = newblock(NULL, NULL, 0); + b = newblock(0); if (b == NULL) { Py_DECREF(deque); return NULL; } + MARK_END(b->leftlink); + MARK_END(b->rightlink); assert(BLOCKLEN >= 2); deque->leftblock = b; @@ -177,7 +200,8 @@ prevblock = deque->rightblock->leftlink; assert(deque->leftblock != deque->rightblock); freeblock(deque->rightblock); - prevblock->rightlink = NULL; + CHECK_NOT_END(prevblock); + MARK_END(prevblock->rightlink); deque->rightblock = prevblock; deque->rightindex = BLOCKLEN - 1; } @@ -214,8 +238,8 @@ assert(deque->leftblock != deque->rightblock); prevblock = deque->leftblock->rightlink; freeblock(deque->leftblock); - assert(prevblock != NULL); - prevblock->leftlink = NULL; + CHECK_NOT_END(prevblock); + MARK_END(prevblock->leftlink); deque->leftblock = prevblock; deque->leftindex = 0; } @@ -230,12 +254,14 @@ { deque->state++; if (deque->rightindex == BLOCKLEN-1) { - block *b = newblock(deque->rightblock, NULL, Py_SIZE(deque)); + block *b = newblock(Py_SIZE(deque)); if (b == NULL) return NULL; - assert(deque->rightblock->rightlink == NULL); + b->leftlink = deque->rightblock; + CHECK_END(deque->rightblock->rightlink); deque->rightblock->rightlink = b; deque->rightblock = b; + MARK_END(b->rightlink); deque->rightindex = -1; } Py_INCREF(item); @@ -253,12 +279,14 @@ { deque->state++; if (deque->leftindex == 0) { - block *b = newblock(NULL, deque->leftblock, Py_SIZE(deque)); + block *b = newblock(Py_SIZE(deque)); if (b == NULL) return NULL; - assert(deque->leftblock->leftlink == NULL); + b->rightlink = deque->leftblock; + CHECK_END(deque->leftblock->leftlink); deque->leftblock->leftlink = b; deque->leftblock = b; + MARK_END(b->leftlink); deque->leftindex = BLOCKLEN; } Py_INCREF(item); @@ -314,16 +342,17 @@ while ((item = PyIter_Next(it)) != NULL) { deque->state++; if (deque->rightindex == BLOCKLEN-1) { - block *b = newblock(deque->rightblock, NULL, - Py_SIZE(deque)); + block *b = newblock(Py_SIZE(deque)); if (b == NULL) { Py_DECREF(item); Py_DECREF(it); return NULL; } - assert(deque->rightblock->rightlink == NULL); + b->leftlink = deque->rightblock; + CHECK_END(deque->rightblock->rightlink); deque->rightblock->rightlink = b; deque->rightblock = b; + MARK_END(b->rightlink); deque->rightindex = -1; } Py_SIZE(deque)++; @@ -366,16 +395,17 @@ while ((item = PyIter_Next(it)) != NULL) { deque->state++; if (deque->leftindex == 0) { - block *b = newblock(NULL, deque->leftblock, - Py_SIZE(deque)); + block *b = newblock(Py_SIZE(deque)); if (b == NULL) { Py_DECREF(item); Py_DECREF(it); return NULL; } - assert(deque->leftblock->leftlink == NULL); + b->rightlink = deque->leftblock; + CHECK_END(deque->leftblock->leftlink); deque->leftblock->leftlink = b; deque->leftblock = b; + MARK_END(b->leftlink); deque->leftindex = BLOCKLEN; } Py_SIZE(deque)++; @@ -430,14 +460,16 @@ deque->state++; while (n > 0) { if (leftindex == 0) { - block *b = newblock(NULL, leftblock, len); + block *b = newblock(len); if (b == NULL) { rv = -1; goto done; } - assert(leftblock->leftlink == NULL); + b->rightlink = leftblock; + CHECK_END(leftblock->leftlink); leftblock->leftlink = b; leftblock = b; + MARK_END(b->leftlink); leftindex = BLOCKLEN; } assert(leftindex > 0); @@ -462,24 +494,26 @@ if (rightindex == -1) { block *prevblock = rightblock->leftlink; - assert(rightblock != NULL); assert(leftblock != rightblock); freeblock(rightblock); - prevblock->rightlink = NULL; + CHECK_NOT_END(prevblock); + MARK_END(prevblock->rightlink); rightblock = prevblock; rightindex = BLOCKLEN - 1; } } while (n < 0) { if (rightindex == BLOCKLEN - 1) { - block *b = newblock(rightblock, NULL, len); + block *b = newblock(len); if (b == NULL) { rv = -1; goto done; } - assert(rightblock->rightlink == NULL); + b->leftlink = rightblock; + CHECK_END(rightblock->rightlink); rightblock->rightlink = b; rightblock = b; + MARK_END(b->rightlink); rightindex = -1; } assert (rightindex < BLOCKLEN - 1); @@ -506,8 +540,8 @@ block *nextblock = leftblock->rightlink; assert(leftblock != rightblock); freeblock(leftblock); - assert(nextblock != NULL); - nextblock->leftlink = NULL; + CHECK_NOT_END(nextblock); + MARK_END(nextblock->leftlink); leftblock = nextblock; leftindex = 0; } @@ -550,8 +584,8 @@ for (i=0 ; idata[leftindex]; @@ -591,7 +625,7 @@ int cmp; for (i=0 ; idata[index]; cmp = PyObject_RichCompareBool(item, v, Py_EQ); if (cmp > 0) @@ -1199,7 +1233,7 @@ it->index++; it->counter--; if (it->index == BLOCKLEN && it->counter > 0) { - assert (it->b->rightlink != NULL); + CHECK_NOT_END(it->b->rightlink); it->b = it->b->rightlink; it->index = 0; } @@ -1341,7 +1375,7 @@ it->index--; it->counter--; if (it->index == -1 && it->counter > 0) { - assert (it->b->leftlink != NULL); + CHECK_NOT_END(it->b->leftlink); it->b = it->b->leftlink; it->index = BLOCKLEN - 1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 14:07:31 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 7 Jul 2013 14:07:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_=23ifdef?= Message-ID: <3bp7pC5pTjzS1v@mail.python.org> http://hg.python.org/cpython/rev/744dd749e25b changeset: 84488:744dd749e25b user: Raymond Hettinger date: Sun Jul 07 02:07:23 2013 -1000 summary: Fix #ifdef files: Modules/_collectionsmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -61,7 +61,7 @@ * block is freed leaving another existing block as the new endpoint. */ -#if Py_DEBUG +#ifdef Py_DEBUG #define MARK_END(link) link = NULL; #define CHECK_END(link) assert(link == NULL); #define CHECK_NOT_END(link) assert(link != NULL); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 15:01:52 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 15:01:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_446=3A_add_a_link_to_=22G?= =?utf-8?q?hosts_of_Unix_past=2C_part_2=3A_Conflated_designs=22_article?= Message-ID: <3bp90w6KQ6zSCB@mail.python.org> http://hg.python.org/peps/rev/a7faa4aa505e changeset: 4983:a7faa4aa505e user: Victor Stinner date: Sun Jul 07 15:00:53 2013 +0200 summary: PEP 446: add a link to "Ghosts of Unix past, part 2: Conflated designs" article (LWN) files: pep-0446.txt | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -221,6 +221,9 @@ * `Secure File Descriptor Handling `_ (Ulrich Drepper, 2008) +* `Ghosts of Unix past, part 2: Conflated designs + `_ (Neil Brown, 2010) explains the + history of ``O_CLOEXEC`` and ``O_NONBLOCK`` flags Copyright -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 7 15:06:11 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 15:06:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_446=3A_add_new_os=2Eget/s?= =?utf-8?q?et=5Fblocking=28=29_functions?= Message-ID: <3bp95v32tDzQNc@mail.python.org> http://hg.python.org/peps/rev/ce61588d244c changeset: 4984:ce61588d244c user: Victor Stinner date: Sun Jul 07 15:05:58 2013 +0200 summary: PEP 446: add new os.get/set_blocking() functions files: pep-0446.txt | 13 +++++++++++-- 1 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -127,21 +127,30 @@ setting close-on-exec and blocking flags at the creation of the file descriptor or socket, the flags are set using additional system calls. + New Functions ------------- Add new functions the get and set the close-on-exec flag of a file -descriptor: +descriptor, available on all platforms: * ``os.get_cloexec(fd:int) -> bool`` * ``os.set_cloexec(fd:int, cloexec: bool)`` +Add new functions the get and set the blocking flag of a file +descriptor, only available on UNIX: + +* ``os.get_blocking(fd:int) -> bool`` +* ``os.set_blocking(fd:int, blocking: bool)`` + Other Changes ------------- The ``subprocess.Popen`` class must clear the close-on-exec flag of file -descriptors of the ``pass_fds`` parameter. +descriptors of the ``pass_fds`` parameter. The flag is cleared in the +child process before executing the program, the change does not change +the flag in the parent process. The close-on-exec flag must also be set on private file descriptors and sockets in the Python standard library. For example, on UNIX, -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 7 15:10:57 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 15:10:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_446=3A_typo?= Message-ID: <3bp9CP6DWrz7Ljm@mail.python.org> http://hg.python.org/peps/rev/e91b098137c5 changeset: 4985:e91b098137c5 user: Victor Stinner date: Sun Jul 07 15:10:39 2013 +0200 summary: PEP 446: typo files: pep-0446.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -174,8 +174,8 @@ backward compatibility issue), and is much simpler. -Add blocking parameter for file descriptors and Windows overlapped I/O ----------------------------------------------------------------------- +Add blocking parameter for file descriptors and use Windows overlapped I/O +-------------------------------------------------------------------------- Windows supports non-blocking operations on files using an extension of the Windows API called "Overlapped I/O". Using this extension requires -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 7 16:26:03 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 16:26:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Fix_Py?= =?utf-8?q?=5FFinalize=28=29=3A_destroy_the_GIL_after_the_last_call_to?= Message-ID: <3bpBt36gbRzRCK@mail.python.org> http://hg.python.org/cpython/rev/213d6d7f5979 changeset: 84489:213d6d7f5979 user: Victor Stinner date: Sun Jul 07 15:50:49 2013 +0200 summary: Issue #18203: Fix Py_Finalize(): destroy the GIL after the last call to PyMem_Malloc() or PyObject_Malloc(). For example, PyCFunction_Fini() calls PyObject_GC_Del() which calls PyObject_FREE(). files: Python/pythonrun.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -606,11 +606,6 @@ _PyExc_Fini(); - /* Cleanup auto-thread-state */ -#ifdef WITH_THREAD - _PyGILState_Fini(); -#endif /* WITH_THREAD */ - /* Sundry finalizers */ PyMethod_Fini(); PyFrame_Fini(); @@ -629,10 +624,6 @@ /* 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); @@ -647,6 +638,15 @@ PyGrammar_RemoveAccelerators(&_PyParser_Grammar); + /* Cleanup auto-thread-state */ +#ifdef WITH_THREAD + _PyGILState_Fini(); +#endif /* WITH_THREAD */ + + /* Delete current thread. After this, many C API calls become crashy. */ + PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); + #ifdef Py_TRACE_REFS /* Display addresses (& refcnts) of all objects still alive. * An address can be used to find the repr of the object, printed -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 16:26:05 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 16:26:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Replace_?= =?utf-8?q?malloc=28=29_with_PyMem=5FRawMalloc=28=29_at_Python_initializat?= =?utf-8?q?ion?= Message-ID: <3bpBt54R67zT0x@mail.python.org> http://hg.python.org/cpython/rev/18bb92b0c458 changeset: 84490:18bb92b0c458 user: Victor Stinner date: Sun Jul 07 16:25:15 2013 +0200 summary: Issue #18203: Replace malloc() with PyMem_RawMalloc() at Python initialization * Replace malloc() with PyMem_RawMalloc() * Replace PyMem_Malloc() with PyMem_RawMalloc() where the GIL is not held. * _Py_char2wchar() now returns a buffer allocated by PyMem_RawMalloc(), instead of PyMem_Malloc() files: Modules/getpath.c | 20 ++++++-------- Modules/main.c | 14 +++++----- Modules/python.c | 23 ++++++++++------ Objects/unicodeobject.c | 6 ++-- PC/getpathp.c | 39 +++++++++++++--------------- Python/fileutils.c | 22 ++++++++-------- Python/pystate.c | 20 +++++++------- Python/thread.c | 8 ++-- 8 files changed, 76 insertions(+), 76 deletions(-) diff --git a/Modules/getpath.c b/Modules/getpath.c --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -343,7 +343,7 @@ if (vpath != NULL) { wcscpy(prefix, argv0_path); joinpath(prefix, vpath); - PyMem_Free(vpath); + PyMem_RawFree(vpath); joinpath(prefix, L"Lib"); joinpath(prefix, LANDMARK); if (ismodule(prefix)) @@ -554,8 +554,7 @@ } else progpath[0] = '\0'; - if (path_buffer != NULL) - PyMem_Free(path_buffer); + PyMem_RawFree(path_buffer); if (progpath[0] != SEP && progpath[0] != '\0') absolutize(progpath); wcsncpy(argv0_path, progpath, MAXPATHLEN); @@ -597,7 +596,7 @@ /* Use the location of the library as the progpath */ wcsncpy(argv0_path, wbuf, MAXPATHLEN); } - PyMem_Free(wbuf); + PyMem_RawFree(wbuf); } #endif @@ -808,11 +807,10 @@ else wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN); - PyMem_Free(_pythonpath); - PyMem_Free(_prefix); - PyMem_Free(_exec_prefix); - if (rtpypath != NULL) - PyMem_Free(rtpypath); + PyMem_RawFree(_pythonpath); + PyMem_RawFree(_prefix); + PyMem_RawFree(_exec_prefix); + PyMem_RawFree(rtpypath); } @@ -822,7 +820,7 @@ { if (module_search_path != NULL) { if (module_search_path_malloced) - PyMem_Free(module_search_path); + PyMem_RawFree(module_search_path); module_search_path = NULL; module_search_path_malloced = 0; } @@ -831,7 +829,7 @@ wchar_t *prog = Py_GetProgramName(); wcsncpy(progpath, prog, MAXPATHLEN); exec_prefix[0] = prefix[0] = L'\0'; - module_search_path = PyMem_Malloc((wcslen(path) + 1) * sizeof(wchar_t)); + module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); module_search_path_malloced = 1; if (module_search_path != NULL) wcscpy(module_search_path, path); diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -391,7 +391,7 @@ command to interpret. */ len = wcslen(_PyOS_optarg) + 1 + 1; - command = (wchar_t *)malloc(sizeof(wchar_t) * len); + command = (wchar_t *)PyMem_RawMalloc(sizeof(wchar_t) * len); if (command == NULL) Py_FatalError( "not enough memory to copy -c argument"); @@ -520,7 +520,7 @@ *wp != L'\0') { wchar_t *buf, *warning; - buf = (wchar_t *)malloc((wcslen(wp) + 1) * sizeof(wchar_t)); + buf = (wchar_t *)PyMem_RawMalloc((wcslen(wp) + 1) * sizeof(wchar_t)); if (buf == NULL) Py_FatalError( "not enough memory to copy PYTHONWARNINGS"); @@ -530,7 +530,7 @@ warning = wcstok(NULL, L",")) { PySys_AddWarnOption(warning); } - free(buf); + PyMem_RawFree(buf); } #else if ((p = Py_GETENV("PYTHONWARNINGS")) && *p != '\0') { @@ -539,7 +539,7 @@ /* settle for strtok here as there's no one standard C89 wcstok */ - buf = (char *)malloc(strlen(p) + 1); + buf = (char *)PyMem_RawMalloc(strlen(p) + 1); if (buf == NULL) Py_FatalError( "not enough memory to copy PYTHONWARNINGS"); @@ -563,7 +563,7 @@ } setlocale(LC_ALL, oldloc); free(oldloc); - free(buf); + PyMem_RawFree(buf); } #endif @@ -633,7 +633,7 @@ wchar_t* buffer; size_t len = strlen(p) + 1; - buffer = malloc(len * sizeof(wchar_t)); + buffer = PyMem_RawMalloc(len * sizeof(wchar_t)); if (buffer == NULL) { Py_FatalError( "not enough memory to copy PYTHONEXECUTABLE"); @@ -707,7 +707,7 @@ if (command) { sts = run_command(command, &cf); - free(command); + PyMem_RawFree(command); } else if (module) { sts = (RunModule(module, 1) != 0); } diff --git a/Modules/python.c b/Modules/python.c --- a/Modules/python.c +++ b/Modules/python.c @@ -18,11 +18,19 @@ int main(int argc, char **argv) { - wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); + wchar_t **argv_copy; /* We need a second copies, as Python might modify the first one. */ - wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); + wchar_t **argv_copy2; int i, res; char *oldloc; + + argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); + argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + return 1; + } + /* 754 requires that FP exceptions run in "no stop" mode by default, * and until C vendors implement C99's ways to control FP exceptions, * Python requires non-stop mode. Alas, some platforms enable FP @@ -34,10 +42,7 @@ m = fpgetmask(); fpsetmask(m & ~FP_X_OFL); #endif - if (!argv_copy || !argv_copy2) { - fprintf(stderr, "out of memory\n"); - return 1; - } + oldloc = strdup(setlocale(LC_ALL, NULL)); setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { @@ -57,10 +62,10 @@ free(oldloc); res = Py_Main(argc, argv_copy); for (i = 0; i < argc; i++) { - PyMem_Free(argv_copy2[i]); + PyMem_RawFree(argv_copy2[i]); } - PyMem_Free(argv_copy); - PyMem_Free(argv_copy2); + PyMem_RawFree(argv_copy); + PyMem_RawFree(argv_copy2); return res; } #endif diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3316,7 +3316,7 @@ wstr = _Py_char2wchar(errmsg, &errlen); if (wstr != NULL) { reason = PyUnicode_FromWideChar(wstr, errlen); - PyMem_Free(wstr); + PyMem_RawFree(wstr); } else errmsg = NULL; } @@ -3535,7 +3535,7 @@ } unicode = PyUnicode_FromWideChar(wstr, wlen); - PyMem_Free(wstr); + PyMem_RawFree(wstr); } else { /* strict mode */ @@ -3583,7 +3583,7 @@ wstr = _Py_char2wchar(errmsg, &errlen); if (wstr != NULL) { reason = PyUnicode_FromWideChar(wstr, errlen); - PyMem_Free(wstr); + PyMem_RawFree(wstr); } else errmsg = NULL; } diff --git a/PC/getpathp.c b/PC/getpathp.c --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -245,9 +245,9 @@ /* Tried to use sysget("winver") but here is too early :-( */ versionLen = strlen(PyWin_DLLVersionString); /* Space for all the chars, plus one \0 */ - keyBuf = keyBufPtr = malloc(sizeof(keyPrefix) + - sizeof(WCHAR)*(versionLen-1) + - sizeof(keySuffix)); + keyBuf = keyBufPtr = PyMem_RawMalloc(sizeof(keyPrefix) + + sizeof(WCHAR)*(versionLen-1) + + sizeof(keySuffix)); if (keyBuf==NULL) goto done; memcpy(keyBufPtr, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR)); @@ -271,7 +271,7 @@ /* Allocate a temp array of char buffers, so we only need to loop reading the registry once */ - ppPaths = malloc( sizeof(WCHAR *) * numKeys ); + ppPaths = PyMem_RawMalloc( sizeof(WCHAR *) * numKeys ); if (ppPaths==NULL) goto done; memset(ppPaths, 0, sizeof(WCHAR *) * numKeys); /* Loop over all subkeys, allocating a temp sub-buffer. */ @@ -293,7 +293,7 @@ /* Find the value of the buffer size, malloc, then read it */ RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize); if (reqdSize) { - ppPaths[index] = malloc(reqdSize); + ppPaths[index] = PyMem_RawMalloc(reqdSize); if (ppPaths[index]) { RegQueryValueExW(subKey, NULL, 0, NULL, (LPBYTE)ppPaths[index], @@ -308,7 +308,7 @@ if (dataSize == 0) goto done; /* original datasize from RegQueryInfo doesn't include the \0 */ - dataBuf = malloc((dataSize+1) * sizeof(WCHAR)); + dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR)); if (dataBuf) { WCHAR *szCur = dataBuf; DWORD reqdSize = dataSize; @@ -346,14 +346,13 @@ done: /* Loop freeing my temp buffers */ if (ppPaths) { - for(index=0;indexnext; HEAD_UNLOCK(); - free(interp); + PyMem_RawFree(interp); #ifdef WITH_THREAD if (interp_head == NULL && head_mutex != NULL) { PyThread_free_lock(head_mutex); @@ -168,7 +168,7 @@ static PyThreadState * new_threadstate(PyInterpreterState *interp, int init) { - PyThreadState *tstate = (PyThreadState *)malloc(sizeof(PyThreadState)); + PyThreadState *tstate = (PyThreadState *)PyMem_RawMalloc(sizeof(PyThreadState)); if (_PyThreadState_GetFrame == NULL) _PyThreadState_GetFrame = threadstate_getframe; @@ -365,7 +365,7 @@ if (tstate->next) tstate->next->prev = tstate->prev; HEAD_UNLOCK(); - free(tstate); + PyMem_RawFree(tstate); } @@ -432,7 +432,7 @@ for (p = garbage; p; p = next) { next = p->next; PyThreadState_Clear(p); - free(p); + PyMem_RawFree(p); } } diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -231,7 +231,7 @@ assert(p == NULL); goto Done; } - p = (struct key *)malloc(sizeof(struct key)); + p = (struct key *)PyMem_RawMalloc(sizeof(struct key)); if (p != NULL) { p->id = id; p->key = key; @@ -270,7 +270,7 @@ while ((p = *q) != NULL) { if (p->key == key) { *q = p->next; - free((void *)p); + PyMem_RawFree((void *)p); /* NB This does *not* free p->value! */ } else @@ -324,7 +324,7 @@ while ((p = *q) != NULL) { if (p->key == key && p->id == id) { *q = p->next; - free((void *)p); + PyMem_RawFree((void *)p); /* NB This does *not* free p->value! */ break; } @@ -357,7 +357,7 @@ while ((p = *q) != NULL) { if (p->id != id) { *q = p->next; - free((void *)p); + PyMem_RawFree((void *)p); /* NB This does *not* free p->value! */ } else -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 16:26:07 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 16:26:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Replace_?= =?utf-8?q?malloc=28=29_with_PyMem=5FMalloc=28=29_in_Python_modules?= Message-ID: <3bpBt716S4zSnC@mail.python.org> http://hg.python.org/cpython/rev/41ef797e6639 changeset: 84491:41ef797e6639 user: Victor Stinner date: Sun Jul 07 16:21:41 2013 +0200 summary: Issue #18203: Replace malloc() with PyMem_Malloc() in Python modules Replace malloc() with PyMem_Malloc() when the GIL is held, or with PyMem_RawMalloc() otherwise. files: Modules/_curses_panel.c | 6 ++-- Modules/_cursesmodule.c | 4 +- Modules/_lsprof.c | 18 +++++++------- Modules/_ssl.c | 4 +- Modules/audioop.c | 10 +++---- Modules/posixmodule.c | 35 ++++++++++++++-------------- Modules/pyexpat.c | 18 +++++++------- Modules/readline.c | 4 +- Modules/zlibmodule.c | 4 +- PC/winreg.c | 4 +- 10 files changed, 52 insertions(+), 55 deletions(-) diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -117,7 +117,7 @@ { list_of_panels *new; - if ((new = (list_of_panels *)malloc(sizeof(list_of_panels))) == NULL) { + if ((new = (list_of_panels *)PyMem_Malloc(sizeof(list_of_panels))) == NULL) { PyErr_NoMemory(); return -1; } @@ -136,7 +136,7 @@ temp = lop; if (temp->po == po) { lop = temp->next; - free(temp); + PyMem_Free(temp); return; } while (temp->next == NULL || temp->next->po != po) { @@ -148,7 +148,7 @@ temp = temp->next; } n = temp->next->next; - free(temp->next); + PyMem_Free(temp->next); temp->next = n; return; } diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3406,7 +3406,7 @@ continue; if (strncmp(key_n,"KEY_F(",6)==0) { char *p1, *p2; - key_n2 = malloc(strlen(key_n)+1); + key_n2 = PyMem_Malloc(strlen(key_n)+1); if (!key_n2) { PyErr_NoMemory(); break; @@ -3425,7 +3425,7 @@ key_n2 = key_n; SetDictInt(key_n2,key); if (key_n2 != key_n) - free(key_n2); + PyMem_Free(key_n2); } #endif SetDictInt("KEY_MIN", KEY_MIN); diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -223,7 +223,7 @@ newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj) { ProfilerEntry *self; - self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry)); + self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry)); if (self == NULL) { pObj->flags |= POF_NOMEMORY; return NULL; @@ -231,7 +231,7 @@ userObj = normalizeUserObj(userObj); if (userObj == NULL) { PyErr_Clear(); - free(self); + PyMem_Free(self); pObj->flags |= POF_NOMEMORY; return NULL; } @@ -264,7 +264,7 @@ newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry) { ProfilerSubEntry *self; - self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry)); + self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry)); if (self == NULL) { pObj->flags |= POF_NOMEMORY; return NULL; @@ -282,7 +282,7 @@ static int freeSubEntry(rotating_node_t *header, void *arg) { ProfilerSubEntry *subentry = (ProfilerSubEntry*) header; - free(subentry); + PyMem_Free(subentry); return 0; } @@ -291,7 +291,7 @@ ProfilerEntry *entry = (ProfilerEntry*) header; RotatingTree_Enum(entry->calls, freeSubEntry, NULL); Py_DECREF(entry->userObj); - free(entry); + PyMem_Free(entry); return 0; } @@ -301,13 +301,13 @@ pObj->profilerEntries = EMPTY_ROTATING_TREE; /* release the memory hold by the ProfilerContexts */ if (pObj->currentProfilerContext) { - free(pObj->currentProfilerContext); + PyMem_Free(pObj->currentProfilerContext); pObj->currentProfilerContext = NULL; } while (pObj->freelistProfilerContext) { ProfilerContext *c = pObj->freelistProfilerContext; pObj->freelistProfilerContext = c->previous; - free(c); + PyMem_Free(c); } pObj->freelistProfilerContext = NULL; } @@ -393,7 +393,7 @@ else { /* free list exhausted, allocate a new one */ pContext = (ProfilerContext*) - malloc(sizeof(ProfilerContext)); + PyMem_Malloc(sizeof(ProfilerContext)); if (pContext == NULL) { pObj->flags |= POF_NOMEMORY; goto restorePyerr; @@ -712,7 +712,7 @@ else pObj->currentProfilerContext = pContext->previous; if (pContext) - free(pContext); + PyMem_Free(pContext); } } diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3118,7 +3118,7 @@ if (_ssl_locks == NULL) { _ssl_locks_count = CRYPTO_num_locks(); _ssl_locks = (PyThread_type_lock *) - malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); + PyMem_Malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); if (_ssl_locks == NULL) return 0; memset(_ssl_locks, 0, @@ -3130,7 +3130,7 @@ for (j = 0; j < i; j++) { PyThread_free_lock(_ssl_locks[j]); } - free(_ssl_locks); + PyMem_Free(_ssl_locks); return 0; } } diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1137,8 +1137,8 @@ "not enough memory for output buffer"); return 0; } - prev_i = (int *) malloc(nchannels * sizeof(int)); - cur_i = (int *) malloc(nchannels * sizeof(int)); + prev_i = (int *) PyMem_Malloc(nchannels * sizeof(int)); + cur_i = (int *) PyMem_Malloc(nchannels * sizeof(int)); if (prev_i == NULL || cur_i == NULL) { (void) PyErr_NoMemory(); goto exit; @@ -1257,10 +1257,8 @@ } } exit: - if (prev_i != NULL) - free(prev_i); - if (cur_i != NULL) - free(cur_i); + PyMem_Free(prev_i); + PyMem_Free(cur_i); return rv; } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1298,14 +1298,14 @@ if (!result) return FALSE; if (result > MAX_PATH+1) { - new_path = malloc(result * sizeof(wchar_t)); + new_path = PyMem_RawMalloc(result * sizeof(wchar_t)); if (!new_path) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } result = GetCurrentDirectoryW(result, new_path); if (!result) { - free(new_path); + PyMem_RawFree(new_path); return FALSE; } } @@ -1316,7 +1316,7 @@ env[1] = new_path[0]; result = SetEnvironmentVariableW(env, new_path); if (new_path != _new_path) - free(new_path); + PyMem_RawFree(new_path); return result; } #endif @@ -1497,7 +1497,7 @@ if(!buf_size) return FALSE; - buf = (wchar_t *)malloc((buf_size+1)*sizeof(wchar_t)); + buf = (wchar_t *)PyMem_Malloc((buf_size+1)*sizeof(wchar_t)); if (!buf) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -1507,12 +1507,12 @@ buf, buf_size, VOLUME_NAME_DOS); if(!result_length) { - free(buf); + PyMem_Free(buf); return FALSE; } if(!CloseHandle(hdl)) { - free(buf); + PyMem_Free(buf); return FALSE; } @@ -1603,7 +1603,7 @@ return -1; code = win32_xstat_impl_w(target_path, result, FALSE); - free(target_path); + PyMem_Free(target_path); return code; } } else @@ -1699,7 +1699,7 @@ return -1; code = win32_xstat_impl_w(target_path, result, FALSE); - free(target_path); + PyMem_Free(target_path); return code; } } else @@ -3089,7 +3089,7 @@ terminating \0. If the buffer is too small, len includes the space needed for the terminator. */ if (len >= sizeof wbuf/ sizeof wbuf[0]) { - wbuf2 = malloc(len * sizeof(wchar_t)); + wbuf2 = PyMem_RawMalloc(len * sizeof(wchar_t)); if (wbuf2) len = GetCurrentDirectoryW(len, wbuf2); } @@ -3100,12 +3100,12 @@ } if (!len) { if (wbuf2 != wbuf) - free(wbuf2); + PyMem_RawFree(wbuf2); return PyErr_SetFromWindowsErr(0); } resobj = PyUnicode_FromWideChar(wbuf2, len); if (wbuf2 != wbuf) - free(wbuf2); + PyMem_RawFree(wbuf2); return resobj; } @@ -3289,7 +3289,7 @@ len = wcslen(path->wide); } /* The +5 is so we can append "\\*.*\0" */ - wnamebuf = malloc((len + 5) * sizeof(wchar_t)); + wnamebuf = PyMem_Malloc((len + 5) * sizeof(wchar_t)); if (!wnamebuf) { PyErr_NoMemory(); goto exit; @@ -3410,8 +3410,7 @@ } } } - if (wnamebuf) - free(wnamebuf); + PyMem_Free(wnamebuf); return list; } /* end of _listdir_windows_no_opendir */ @@ -3575,7 +3574,7 @@ Py_ARRAY_LENGTH(woutbuf), woutbuf, &wtemp); if (result > Py_ARRAY_LENGTH(woutbuf)) { - woutbufp = malloc(result * sizeof(wchar_t)); + woutbufp = PyMem_Malloc(result * sizeof(wchar_t)); if (!woutbufp) return PyErr_NoMemory(); result = GetFullPathNameW(wpath, result, woutbufp, &wtemp); @@ -3585,7 +3584,7 @@ else v = win32_error_object("GetFullPathNameW", po); if (woutbufp != woutbuf) - free(woutbufp); + PyMem_Free(woutbufp); return v; } /* Drop the argument parsing error as narrow strings @@ -3655,7 +3654,7 @@ if(!buf_size) return win32_error_object("GetFinalPathNameByHandle", po); - target_path = (wchar_t *)malloc((buf_size+1)*sizeof(wchar_t)); + target_path = (wchar_t *)PyMem_Malloc((buf_size+1)*sizeof(wchar_t)); if(!target_path) return PyErr_NoMemory(); @@ -3669,7 +3668,7 @@ target_path[result_length] = 0; result = PyUnicode_FromWideChar(target_path, result_length); - free(target_path); + PyMem_Free(target_path); return result; } /* end of posix__getfinalpathname */ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -997,7 +997,7 @@ PyObject_GC_Track(new_parser); if (self->buffer != NULL) { - new_parser->buffer = malloc(new_parser->buffer_size); + new_parser->buffer = PyMem_Malloc(new_parser->buffer_size); if (new_parser->buffer == NULL) { Py_DECREF(new_parser); return PyErr_NoMemory(); @@ -1014,7 +1014,7 @@ for (i = 0; handler_info[i].name != NULL; i++) /* do nothing */; - new_parser->handlers = malloc(sizeof(PyObject *) * i); + new_parser->handlers = PyMem_Malloc(sizeof(PyObject *) * i); if (!new_parser->handlers) { Py_DECREF(new_parser); return PyErr_NoMemory(); @@ -1206,7 +1206,7 @@ for (i = 0; handler_info[i].name != NULL; i++) /* do nothing */; - self->handlers = malloc(sizeof(PyObject *) * i); + self->handlers = PyMem_Malloc(sizeof(PyObject *) * i); if (!self->handlers) { Py_DECREF(self); return PyErr_NoMemory(); @@ -1233,11 +1233,11 @@ self->handlers[i] = NULL; Py_XDECREF(temp); } - free(self->handlers); + PyMem_Free(self->handlers); self->handlers = NULL; } if (self->buffer != NULL) { - free(self->buffer); + PyMem_Free(self->buffer); self->buffer = NULL; } Py_XDECREF(self->intern); @@ -1437,7 +1437,7 @@ return -1; if (b) { if (self->buffer == NULL) { - self->buffer = malloc(self->buffer_size); + self->buffer = PyMem_Malloc(self->buffer_size); if (self->buffer == NULL) { PyErr_NoMemory(); return -1; @@ -1448,7 +1448,7 @@ else if (self->buffer != NULL) { if (flush_character_buffer(self) < 0) return -1; - free(self->buffer); + PyMem_Free(self->buffer); self->buffer = NULL; } return 0; @@ -1508,9 +1508,9 @@ flush_character_buffer(self); } /* free existing buffer */ - free(self->buffer); + PyMem_Free(self->buffer); } - self->buffer = malloc(new_buffer_size); + self->buffer = PyMem_Malloc(new_buffer_size); if (self->buffer == NULL) { PyErr_NoMemory(); return -1; diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -84,12 +84,12 @@ return NULL; /* Make a copy -- rl_parse_and_bind() modifies its argument */ /* Bernard Herzog */ - copy = malloc(1 + strlen(s)); + copy = PyMem_Malloc(1 + strlen(s)); if (copy == NULL) return PyErr_NoMemory(); strcpy(copy, s); rl_parse_and_bind(copy); - free(copy); /* Free the copy */ + PyMem_Free(copy); /* Free the copy */ Py_RETURN_NONE; } diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -165,7 +165,7 @@ zst.avail_out = length + length/1000 + 12 + 1; - output = (Byte*)malloc(zst.avail_out); + output = (Byte*)PyMem_Malloc(zst.avail_out); if (output == NULL) { PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); @@ -218,7 +218,7 @@ error: PyBuffer_Release(&pinput); - free(output); + PyMem_Free(output); return ReturnVal; } diff --git a/PC/winreg.c b/PC/winreg.c --- a/PC/winreg.c +++ b/PC/winreg.c @@ -938,7 +938,7 @@ wchar_t *data = (wchar_t *)retDataBuf; int len = retDataSize / 2; int s = countStrings(data, len); - wchar_t **str = (wchar_t **)malloc(sizeof(wchar_t *)*s); + wchar_t **str = (wchar_t **)PyMem_Malloc(sizeof(wchar_t *)*s); if (str == NULL) return PyErr_NoMemory(); @@ -959,7 +959,7 @@ index, PyUnicode_FromWideChar(str[index], len)); } - free(str); + PyMem_Free(str); break; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 16:36:08 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 16:36:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_a_compiler_warning_in_?= =?utf-8?q?posix=5Fsendfile=28=29_on_FreeBSD=3A?= Message-ID: <3bpC5h0GFqzQ1R@mail.python.org> http://hg.python.org/cpython/rev/adafc38852c4 changeset: 84492:adafc38852c4 user: Victor Stinner date: Sun Jul 07 16:32:36 2013 +0200 summary: Fix a compiler warning in posix_sendfile() on FreeBSD: Modules/posixmodule.c: In function 'posix_sendfile': Modules/posixmodule.c:7700: warning: ISO C90 forbids mixed declarations and code files: Modules/posixmodule.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7695,12 +7695,13 @@ off_t sbytes; struct sf_hdtr sf; int flags = 0; - sf.headers = NULL; - sf.trailers = NULL; static char *keywords[] = {"out", "in", "offset", "count", "headers", "trailers", "flags", NULL}; + sf.headers = NULL; + sf.trailers = NULL; + #ifdef __APPLE__ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iiO&O&|OOi:sendfile", keywords, &out, &in, _parse_off_t, &offset, _parse_off_t, &sbytes, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 16:36:09 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 16:36:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Fix_deco?= =?utf-8?q?de=5Fascii=5Fsurrogateescape=28=29=2C_use_PyMem=5FRawMalloc=28?= =?utf-8?q?=29_as?= Message-ID: <3bpC5j2W7zzSJT@mail.python.org> http://hg.python.org/cpython/rev/fc01f9497da7 changeset: 84493:fc01f9497da7 user: Victor Stinner date: Sun Jul 07 16:35:54 2013 +0200 summary: Issue #18203: Fix decode_ascii_surrogateescape(), use PyMem_RawMalloc() as _Py_char2wchar() 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 @@ -201,7 +201,7 @@ unsigned char *in; wchar_t *out; - res = PyMem_Malloc((strlen(arg)+1)*sizeof(wchar_t)); + res = PyMem_RawMalloc((strlen(arg)+1)*sizeof(wchar_t)); if (!res) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 16:50:41 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 16:50:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318227=3A_Use_PyMe?= =?utf-8?q?m=5FRawAlloc=28=29_in_bz2=2C_lzma_and_zlib_modules?= Message-ID: <3bpCQT4y8VzSCB@mail.python.org> http://hg.python.org/cpython/rev/a876d9d2e4fc changeset: 84494:a876d9d2e4fc user: Victor Stinner date: Sun Jul 07 16:50:27 2013 +0200 summary: Issue #18227: Use PyMem_RawAlloc() in bz2, lzma and zlib modules files: Modules/_bz2module.c | 21 ++++++++++++++++++ Modules/_lzmamodule.c | 28 ++++++++++++++++++++++++ Modules/zlibmodule.c | 36 ++++++++++++++++++++++++------ 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -248,6 +248,24 @@ return result; } +static void* +BZ2_Malloc(void* ctx, int items, int size) +{ + if (items < 0 || size < 0) + return NULL; + if ((size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size) + return NULL; + /* PyMem_Malloc() cannot be used: compress() and decompress() + release the GIL */ + return PyMem_RawMalloc(items * size); +} + +static void +BZ2_Free(void* ctx, void *ptr) +{ + return PyMem_RawFree(ptr); +} + static int BZ2Compressor_init(BZ2Compressor *self, PyObject *args, PyObject *kwargs) { @@ -270,6 +288,9 @@ } #endif + self->bzs.opaque = NULL; + self->bzs.bzalloc = BZ2_Malloc; + self->bzs.bzfree = BZ2_Free; bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0); if (catch_bz2_error(bzerror)) goto error; diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -51,6 +51,7 @@ typedef struct { PyObject_HEAD + lzma_allocator alloc; lzma_stream lzs; int flushed; #ifdef WITH_THREAD @@ -60,6 +61,7 @@ typedef struct { PyObject_HEAD + lzma_allocator alloc; lzma_stream lzs; int check; char eof; @@ -117,6 +119,22 @@ } } +static void* +PyLzma_Malloc(void *opaque, size_t items, size_t size) +{ + if (items > (size_t)PY_SSIZE_T_MAX / size) + return NULL; + /* PyMem_Malloc() cannot be used: + the GIL is not held when lzma_code() is called */ + return PyMem_RawMalloc(items * size); +} + +static void +PyLzma_Free(void *opaque, void *ptr) +{ + return PyMem_RawFree(ptr); +} + #if BUFSIZ < 8192 #define INITIAL_BUFFER_SIZE 8192 #else @@ -656,6 +674,11 @@ if (!uint32_converter(preset_obj, &preset)) return -1; + self->alloc.opaque = NULL; + self->alloc.alloc = PyLzma_Malloc; + self->alloc.free = PyLzma_Free; + self->lzs.allocator = &self->alloc; + #ifdef WITH_THREAD self->lock = PyThread_allocate_lock(); if (self->lock == NULL) { @@ -922,6 +945,11 @@ return -1; } + self->alloc.opaque = NULL; + self->alloc.alloc = PyLzma_Malloc; + self->alloc.free = PyLzma_Free; + self->lzs.allocator = &self->alloc; + #ifdef WITH_THREAD self->lock = PyThread_allocate_lock(); if (self->lock == NULL) { diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -136,6 +136,22 @@ return self; } +static void* +PyZlib_Malloc(voidpf ctx, uInt items, uInt size) +{ + if (items > (size_t)PY_SSIZE_T_MAX / size) + return NULL; + /* PyMem_Malloc() cannot be used: the GIL is not held when + inflate() and deflate() are called */ + return PyMem_RawMalloc(items * size); +} + +static void +PyZlib_Free(voidpf ctx, void *ptr) +{ + return PyMem_RawFree(ptr); +} + PyDoc_STRVAR(compress__doc__, "compress(string[, level]) -- Returned compressed string.\n" "\n" @@ -175,8 +191,9 @@ /* Past the point of no return. From here on out, we need to make sure we clean up mallocs & INCREFs. */ - zst.zalloc = (alloc_func)NULL; - zst.zfree = (free_func)Z_NULL; + zst.opaque = NULL; + zst.zalloc = PyZlib_Malloc; + zst.zfree = PyZlib_Free; zst.next_out = (Byte *)output; zst.next_in = (Byte *)input; zst.avail_in = length; @@ -262,8 +279,9 @@ if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) goto error; - zst.zalloc = (alloc_func)NULL; - zst.zfree = (free_func)Z_NULL; + zst.opaque = NULL; + zst.zalloc = PyZlib_Malloc; + zst.zfree = PyZlib_Free; zst.next_out = (Byte *)PyBytes_AS_STRING(result_str); zst.next_in = (Byte *)input; err = inflateInit2(&zst, wsize); @@ -356,8 +374,9 @@ self = newcompobject(&Comptype); if (self==NULL) goto error; - self->zst.zalloc = (alloc_func)NULL; - self->zst.zfree = (free_func)Z_NULL; + self->zst.opaque = NULL; + self->zst.zalloc = PyZlib_Malloc; + self->zst.zfree = PyZlib_Free; self->zst.next_in = NULL; self->zst.avail_in = 0; err = deflateInit2(&self->zst, level, method, wbits, memLevel, strategy); @@ -420,8 +439,9 @@ self = newcompobject(&Decomptype); if (self == NULL) return(NULL); - self->zst.zalloc = (alloc_func)NULL; - self->zst.zfree = (free_func)Z_NULL; + self->zst.opaque = NULL; + self->zst.zalloc = PyZlib_Malloc; + self->zst.zfree = PyZlib_Free; self->zst.next_in = NULL; self->zst.avail_in = 0; if (zdict != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 17:26:33 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 17:26:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Replace_?= =?utf-8?q?malloc=28=29_with_PyMem=5FMalloc=28=29_in_=5Fssl_for_the_passwo?= =?utf-8?q?rd?= Message-ID: <3bpDCs1w59zRk0@mail.python.org> http://hg.python.org/cpython/rev/638d43665356 changeset: 84495:638d43665356 user: Victor Stinner date: Sun Jul 07 17:07:52 2013 +0200 summary: Issue #18203: Replace malloc() with PyMem_Malloc() in _ssl for the password files: Modules/_ssl.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2070,8 +2070,8 @@ goto error; } - free(pw_info->password); - pw_info->password = malloc(size); + PyMem_Free(pw_info->password); + pw_info->password = PyMem_Malloc(size); if (!pw_info->password) { PyErr_SetString(PyExc_MemoryError, "unable to allocate password buffer"); @@ -2215,13 +2215,13 @@ } SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); - free(pw_info.password); + PyMem_Free(pw_info.password); Py_RETURN_NONE; error: SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); - free(pw_info.password); + PyMem_Free(pw_info.password); Py_XDECREF(keyfile_bytes); Py_XDECREF(certfile_bytes); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 17:26:34 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 17:26:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318227=3A_=22Free?= =?utf-8?q?=22_function_of_bz2=2C_lzma_and_zlib_modules_has_no_return_valu?= =?utf-8?q?e?= Message-ID: <3bpDCt4DHhzS4x@mail.python.org> http://hg.python.org/cpython/rev/12f26c356611 changeset: 84496:12f26c356611 user: Victor Stinner date: Sun Jul 07 17:10:34 2013 +0200 summary: Issue #18227: "Free" function of bz2, lzma and zlib modules has no return value (void) files: Modules/_bz2module.c | 2 +- Modules/_lzmamodule.c | 2 +- Modules/zlibmodule.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -263,7 +263,7 @@ static void BZ2_Free(void* ctx, void *ptr) { - return PyMem_RawFree(ptr); + PyMem_RawFree(ptr); } static int diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -132,7 +132,7 @@ static void PyLzma_Free(void *opaque, void *ptr) { - return PyMem_RawFree(ptr); + PyMem_RawFree(ptr); } #if BUFSIZ < 8192 diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -149,7 +149,7 @@ static void PyZlib_Free(voidpf ctx, void *ptr) { - return PyMem_RawFree(ptr); + PyMem_RawFree(ptr); } PyDoc_STRVAR(compress__doc__, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 17:26:35 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 17:26:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Replace_?= =?utf-8?q?malloc=28=29_with_PyMem=5FRawMalloc=28=29_to_allocate_thread_lo?= =?utf-8?q?cks?= Message-ID: <3bpDCv6RVpzSbH@mail.python.org> http://hg.python.org/cpython/rev/9af1905f20af changeset: 84497:9af1905f20af user: Victor Stinner date: Sun Jul 07 17:17:59 2013 +0200 summary: Issue #18203: Replace malloc() with PyMem_RawMalloc() to allocate thread locks files: Python/thread_nt.h | 8 ++++---- Python/thread_pthread.h | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Python/thread_nt.h b/Python/thread_nt.h --- a/Python/thread_nt.h +++ b/Python/thread_nt.h @@ -34,7 +34,7 @@ PNRMUTEX AllocNonRecursiveMutex() { - PNRMUTEX m = (PNRMUTEX)malloc(sizeof(NRMUTEX)); + PNRMUTEX m = (PNRMUTEX)PyMem_RawMalloc(sizeof(NRMUTEX)); if (!m) return NULL; if (PyCOND_INIT(&m->cv)) @@ -46,7 +46,7 @@ m->locked = 0; return m; fail: - free(m); + PyMem_RawFree(m); return NULL; } @@ -56,7 +56,7 @@ if (mutex) { PyCOND_FINI(&mutex->cv); PyMUTEX_FINI(&mutex->cs); - free(mutex); + PyMem_RawFree(mutex); } } @@ -107,7 +107,7 @@ result = PyCOND_SIGNAL(&mutex->cv); result &= PyMUTEX_UNLOCK(&mutex->cs); return result; -} +} #else /* if ! _PY_USE_CV_LOCKS */ diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -282,14 +282,14 @@ if (!initialized) PyThread_init_thread(); - lock = (sem_t *)malloc(sizeof(sem_t)); + lock = (sem_t *)PyMem_RawMalloc(sizeof(sem_t)); if (lock) { status = sem_init(lock,0,1); CHECK_STATUS("sem_init"); if (error) { - free((void *)lock); + PyMem_RawFree((void *)lock); lock = NULL; } } @@ -313,7 +313,7 @@ status = sem_destroy(thelock); CHECK_STATUS("sem_destroy"); - free((void *)thelock); + PyMem_RawFree((void *)thelock); } /* @@ -410,7 +410,7 @@ if (!initialized) PyThread_init_thread(); - lock = (pthread_lock *) malloc(sizeof(pthread_lock)); + lock = (pthread_lock *) PyMem_RawMalloc(sizeof(pthread_lock)); if (lock) { memset((void *)lock, '\0', sizeof(pthread_lock)); lock->locked = 0; @@ -430,7 +430,7 @@ CHECK_STATUS("pthread_cond_init"); if (error) { - free((void *)lock); + PyMem_RawFree((void *)lock); lock = 0; } } @@ -457,7 +457,7 @@ status = pthread_mutex_destroy( &thelock->mut ); CHECK_STATUS("pthread_mutex_destroy"); - free((void *)thelock); + PyMem_RawFree((void *)thelock); } PyLockStatus -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 17:26:37 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 17:26:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Replace_?= =?utf-8?q?malloc=28=29_with_PyMem=5FMalloc=28=29_to_allocate_arena_object?= =?utf-8?q?s?= Message-ID: <3bpDCx1Pn3zS4x@mail.python.org> http://hg.python.org/cpython/rev/fb7d346b45fa changeset: 84498:fb7d346b45fa user: Victor Stinner date: Sun Jul 07 17:18:53 2013 +0200 summary: Issue #18203: Replace malloc() with PyMem_Malloc() to allocate arena objects files: Python/pyarena.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Python/pyarena.c b/Python/pyarena.c --- a/Python/pyarena.c +++ b/Python/pyarena.c @@ -77,7 +77,7 @@ { /* Allocate header and block as one unit. ab_mem points just past header. */ - block *b = (block *)malloc(sizeof(block) + size); + block *b = (block *)PyMem_Malloc(sizeof(block) + size); if (!b) return NULL; b->ab_size = size; @@ -92,7 +92,7 @@ block_free(block *b) { while (b) { block *next = b->ab_next; - free(b); + PyMem_Free(b); b = next; } } @@ -127,20 +127,20 @@ PyArena * PyArena_New() { - PyArena* arena = (PyArena *)malloc(sizeof(PyArena)); + PyArena* arena = (PyArena *)PyMem_Malloc(sizeof(PyArena)); if (!arena) return (PyArena*)PyErr_NoMemory(); arena->a_head = block_new(DEFAULT_BLOCK_SIZE); arena->a_cur = arena->a_head; if (!arena->a_head) { - free((void *)arena); + PyMem_Free((void *)arena); return (PyArena*)PyErr_NoMemory(); } arena->a_objects = PyList_New(0); if (!arena->a_objects) { block_free(arena->a_head); - free((void *)arena); + PyMem_Free((void *)arena); return (PyArena*)PyErr_NoMemory(); } #if defined(Py_DEBUG) @@ -173,7 +173,7 @@ */ Py_DECREF(arena->a_objects); - free(arena); + PyMem_Free(arena); } void * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 17:26:38 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 17:26:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A__Replace?= =?utf-8?q?_malloc=28=29_with_PyMem=5FMalloc=28=29_in?= Message-ID: <3bpDCy3h4kzSr1@mail.python.org> http://hg.python.org/cpython/rev/10db0c67fc72 changeset: 84499:10db0c67fc72 user: Victor Stinner date: Sun Jul 07 17:22:41 2013 +0200 summary: Issue #18203: Replace malloc() with PyMem_Malloc() in _PySequence_BytesToCharpArray() files: Objects/abstract.c | 19 +++++++++++-------- 1 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1238,7 +1238,7 @@ to be an int or have an __int__ method. Steals integral's reference. error_format will be used to create the TypeError if integral isn't actually an Integral instance. error_format should be a format string - that can accept a char* naming integral's type. + that can accept a char* naming integral's type. */ static PyObject * convert_integral_to_int(PyObject *integral, const char *error_format) @@ -1257,7 +1257,7 @@ } PyErr_Format(PyExc_TypeError, error_format, Py_TYPE(integral)->tp_name); Py_DECREF(integral); - return NULL; + return NULL; } @@ -2721,8 +2721,8 @@ * NULL terminated string pointers with a NULL char* terminating the array. * (ie: an argv or env list) * - * Memory allocated for the returned list is allocated using malloc() and MUST - * be freed by the caller using a free() loop or _Py_FreeCharPArray(). + * Memory allocated for the returned list is allocated using PyMem_Malloc() + * and MUST be freed by _Py_FreeCharPArray(). */ char *const * _PySequence_BytesToCharpArray(PyObject* self) @@ -2730,6 +2730,7 @@ char **array; Py_ssize_t i, argc; PyObject *item = NULL; + Py_ssize_t size; argc = PySequence_Size(self); if (argc == -1) @@ -2742,7 +2743,7 @@ return NULL; } - array = malloc((argc + 1) * sizeof(char *)); + array = PyMem_Malloc((argc + 1) * sizeof(char *)); if (array == NULL) { PyErr_NoMemory(); return NULL; @@ -2761,11 +2762,13 @@ array[i] = NULL; goto fail; } - array[i] = strdup(data); + size = PyBytes_GET_SIZE(item) + 1; + array[i] = PyMem_Malloc(size); if (!array[i]) { PyErr_NoMemory(); goto fail; } + memcpy(array[i], data, size); Py_DECREF(item); } array[argc] = NULL; @@ -2785,7 +2788,7 @@ { Py_ssize_t i; for (i = 0; array[i] != NULL; ++i) { - free(array[i]); + PyMem_Free(array[i]); } - free((void*)array); + PyMem_Free((void*)array); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 17:35:20 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 7 Jul 2013 17:35:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318227=3A_pyexpat_?= =?utf-8?q?now_uses_a_static_XML=5FMemory=5FHandling=5FSuite=2E_cElementTr?= =?utf-8?q?ee?= Message-ID: <3bpDQ03GzTzR4L@mail.python.org> http://hg.python.org/cpython/rev/7f17c67b5bf6 changeset: 84500:7f17c67b5bf6 user: Christian Heimes date: Sun Jul 07 17:35:11 2013 +0200 summary: Issue #18227: pyexpat now uses a static XML_Memory_Handling_Suite. cElementTree uses the same approach since at least Python 2.6 files: Modules/pyexpat.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -10,6 +10,9 @@ #define FIX_TRACE +static XML_Memory_Handling_Suite ExpatMemoryHandler = { + PyObject_Malloc, PyObject_Realloc, PyObject_Free}; + enum HandlerTypes { StartElement, EndElement, @@ -1177,12 +1180,9 @@ self->in_callback = 0; self->ns_prefixes = 0; self->handlers = NULL; - if (namespace_separator != NULL) { - self->itself = XML_ParserCreateNS(encoding, *namespace_separator); - } - else { - self->itself = XML_ParserCreate(encoding); - } + /* namespace_separator is either NULL or contains one char + \0 */ + self->itself = XML_ParserCreate_MM(encoding, &ExpatMemoryHandler, + namespace_separator); #if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) /* This feature was added upstream in libexpat 2.1.0. Our expat copy * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 22:58:06 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 22:58:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Fix_=5FP?= =?utf-8?q?y=5FDecodeUTF8=5Fsurrogateescape=28=29=2C_use_PyMem=5FRawMalloc?= =?utf-8?b?KCkgYXM=?= Message-ID: <3bpMZQ44RXzSCh@mail.python.org> http://hg.python.org/cpython/rev/31a635303e55 changeset: 84501:31a635303e55 user: Victor Stinner date: Sun Jul 07 22:57:45 2013 +0200 summary: Issue #18203: Fix _Py_DecodeUTF8_surrogateescape(), use PyMem_RawMalloc() as _Py_char2wchar() files: Objects/unicodeobject.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4806,7 +4806,7 @@ used to decode the command line arguments on Mac OS X. Return a pointer to a newly allocated wide character string (use - PyMem_Free() to free the memory), or NULL on memory allocation error. */ + PyMem_RawFree() to free the memory), or NULL on memory allocation error. */ wchar_t* _Py_DecodeUTF8_surrogateescape(const char *s, Py_ssize_t size) @@ -4819,7 +4819,7 @@ character count */ if (PY_SSIZE_T_MAX / sizeof(wchar_t) < (size + 1)) return NULL; - unicode = PyMem_Malloc((size + 1) * sizeof(wchar_t)); + unicode = PyMem_RawMalloc((size + 1) * sizeof(wchar_t)); if (!unicode) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 7 23:32:58 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 7 Jul 2013 23:32:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Add_=5FP?= =?utf-8?b?eU1lbV9SYXdTdHJkdXAoKSBhbmQgX1B5TWVtX1N0cmR1cCgp?= Message-ID: <3bpNLf4PQnzPrk@mail.python.org> http://hg.python.org/cpython/rev/65f2c92ed079 changeset: 84502:65f2c92ed079 user: Victor Stinner date: Sun Jul 07 23:30:24 2013 +0200 summary: Issue #18203: Add _PyMem_RawStrdup() and _PyMem_Strdup() Replace strdup() with _PyMem_RawStrdup() or _PyMem_Strdup(), depending if the GIL is held or not. files: Include/pymem.h | 3 +++ Modules/_cursesmodule.c | 8 ++++---- Modules/_pickle.c | 12 ++++++------ Modules/faulthandler.c | 11 ++++++----- Modules/main.c | 4 ++-- Modules/python.c | 6 +++--- Objects/obmalloc.c | 28 ++++++++++++++++++++++++++++ Python/pythonrun.c | 21 ++++++++++++--------- 8 files changed, 64 insertions(+), 29 deletions(-) diff --git a/Include/pymem.h b/Include/pymem.h --- a/Include/pymem.h +++ b/Include/pymem.h @@ -58,6 +58,9 @@ PyAPI_FUNC(void *) PyMem_Realloc(void *ptr, size_t new_size); PyAPI_FUNC(void) PyMem_Free(void *ptr); +PyAPI_FUNC(char *) _PyMem_RawStrdup(const char *str); +PyAPI_FUNC(char *) _PyMem_Strdup(const char *str); + /* Macros. */ /* PyMem_MALLOC(0) means malloc(1). Some systems would return NULL diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -529,7 +529,7 @@ wo = PyObject_NEW(PyCursesWindowObject, &PyCursesWindow_Type); if (wo == NULL) return NULL; wo->win = win; - wo->encoding = strdup(encoding); + wo->encoding = _PyMem_Strdup(encoding); if (wo->encoding == NULL) { Py_DECREF(wo); PyErr_NoMemory(); @@ -543,7 +543,7 @@ { if (wo->win != stdscr) delwin(wo->win); if (wo->encoding != NULL) - free(wo->encoding); + PyMem_Free(wo->encoding); PyObject_DEL(wo); } @@ -1938,13 +1938,13 @@ ascii = PyUnicode_AsASCIIString(value); if (ascii == NULL) return -1; - encoding = strdup(PyBytes_AS_STRING(ascii)); + encoding = _PyMem_Strdup(PyBytes_AS_STRING(ascii)); Py_DECREF(ascii); if (encoding == NULL) { PyErr_NoMemory(); return -1; } - free(self->encoding); + PyMem_Free(self->encoding); self->encoding = encoding; return 0; } diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1213,8 +1213,8 @@ if (errors == NULL) errors = "strict"; - self->encoding = strdup(encoding); - self->errors = strdup(errors); + self->encoding = _PyMem_Strdup(encoding); + self->errors = _PyMem_Strdup(errors); if (self->encoding == NULL || self->errors == NULL) { PyErr_NoMemory(); return -1; @@ -5590,8 +5590,8 @@ _Unpickler_MemoCleanup(self); PyMem_Free(self->marks); PyMem_Free(self->input_line); - free(self->encoding); - free(self->errors); + PyMem_Free(self->encoding); + PyMem_Free(self->errors); Py_TYPE(self)->tp_free((PyObject *)self); } @@ -5627,9 +5627,9 @@ self->marks = NULL; PyMem_Free(self->input_line); self->input_line = NULL; - free(self->encoding); + PyMem_Free(self->encoding); self->encoding = NULL; - free(self->errors); + PyMem_Free(self->errors); self->errors = NULL; return 0; diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -475,7 +475,7 @@ Py_CLEAR(thread.file); if (thread.header) { - free(thread.header); + PyMem_Free(thread.header); thread.header = NULL; } } @@ -504,7 +504,7 @@ "Timeout (%lu:%02lu:%02lu)!\n", hour, min, sec); - return strdup(buffer); + return _PyMem_Strdup(buffer); } static PyObject* @@ -570,7 +570,7 @@ if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) { PyThread_release_lock(thread.running); Py_CLEAR(thread.file); - free(header); + PyMem_Free(header); thread.header = NULL; PyErr_SetString(PyExc_RuntimeError, "unable to start watchdog thread"); @@ -729,9 +729,10 @@ return NULL; if (user_signals == NULL) { - user_signals = calloc(NSIG, sizeof(user_signal_t)); + user_signals = PyMem_Malloc(NSIG * sizeof(user_signal_t)); if (user_signals == NULL) return PyErr_NoMemory(); + memset(user_signals, 0, NSIG * sizeof(user_signal_t)); } user = &user_signals[signum]; @@ -1136,7 +1137,7 @@ if (user_signals != NULL) { for (signum=0; signum < NSIG; signum++) faulthandler_unregister(&user_signals[signum], signum); - free(user_signals); + PyMem_Free(user_signals); user_signals = NULL; } #endif diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -544,7 +544,7 @@ Py_FatalError( "not enough memory to copy PYTHONWARNINGS"); strcpy(buf, p); - oldloc = strdup(setlocale(LC_ALL, NULL)); + oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); setlocale(LC_ALL, ""); for (p = strtok(buf, ","); p != NULL; p = strtok(NULL, ",")) { #ifdef __APPLE__ @@ -562,7 +562,7 @@ Py_DECREF(unicode); } setlocale(LC_ALL, oldloc); - free(oldloc); + PyMem_RawFree(oldloc); PyMem_RawFree(buf); } #endif diff --git a/Modules/python.c b/Modules/python.c --- a/Modules/python.c +++ b/Modules/python.c @@ -43,12 +43,12 @@ fpsetmask(m & ~FP_X_OFL); #endif - oldloc = strdup(setlocale(LC_ALL, NULL)); + oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { argv_copy[i] = _Py_char2wchar(argv[i], NULL); if (!argv_copy[i]) { - free(oldloc); + PyMem_RawFree(oldloc); fprintf(stderr, "Fatal Python error: " "unable to decode the command line argument #%i\n", i + 1); @@ -59,7 +59,7 @@ argv_copy2[argc] = argv_copy[argc] = NULL; setlocale(LC_ALL, oldloc); - free(oldloc); + PyMem_RawFree(oldloc); res = Py_Main(argc, argv_copy); for (i = 0; i < argc; i++) { PyMem_RawFree(argv_copy2[i]); diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -294,6 +294,34 @@ _PyMem.free(_PyMem.ctx, ptr); } +char * +_PyMem_RawStrdup(const char *str) +{ + size_t size; + char *copy; + + size = strlen(str) + 1; + copy = PyMem_RawMalloc(size); + if (copy == NULL) + return NULL; + memcpy(copy, str, size); + return copy; +} + +char * +_PyMem_Strdup(const char *str) +{ + size_t size; + char *copy; + + size = strlen(str) + 1; + copy = PyMem_Malloc(size); + if (copy == NULL) + return NULL; + memcpy(copy, str, size); + return copy; +} + void * PyObject_Malloc(size_t size) { diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -174,7 +174,7 @@ name_utf8 = _PyUnicode_AsString(name); if (name_utf8 == NULL) goto error; - name_str = strdup(name_utf8); + name_str = _PyMem_RawStrdup(name_utf8); Py_DECREF(name); if (name_str == NULL) { PyErr_NoMemory(); @@ -626,7 +626,7 @@ /* reset file system default encoding */ if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) { - free((char*)Py_FileSystemDefaultEncoding); + PyMem_RawFree((char*)Py_FileSystemDefaultEncoding); Py_FileSystemDefaultEncoding = NULL; } @@ -1081,7 +1081,11 @@ encoding = Py_GETENV("PYTHONIOENCODING"); errors = NULL; if (encoding) { - encoding = strdup(encoding); + encoding = _PyMem_Strdup(encoding); + if (encoding == NULL) { + PyErr_NoMemory(); + goto error; + } errors = strchr(encoding, ':'); if (errors) { *errors = '\0'; @@ -1140,10 +1144,10 @@ when import.c tries to write to stderr in verbose mode. */ encoding_attr = PyObject_GetAttrString(std, "encoding"); if (encoding_attr != NULL) { - const char * encoding; - encoding = _PyUnicode_AsString(encoding_attr); - if (encoding != NULL) { - PyObject *codec_info = _PyCodec_Lookup(encoding); + const char * std_encoding; + std_encoding = _PyUnicode_AsString(encoding_attr); + if (std_encoding != NULL) { + PyObject *codec_info = _PyCodec_Lookup(std_encoding); Py_XDECREF(codec_info); } Py_DECREF(encoding_attr); @@ -1160,8 +1164,7 @@ status = -1; } - if (encoding) - free(encoding); + PyMem_Free(encoding); Py_XDECREF(bimod); Py_XDECREF(iomod); return status; -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Jul 8 05:48:29 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 08 Jul 2013 05:48:29 +0200 Subject: [Python-checkins] Daily reference leaks (65f2c92ed079): sum=-855 Message-ID: results for 65f2c92ed079 on branch "default" -------------------------------------------- test_urllib2net leaked [-467, 0, 0] references, sum=-467 test_urllib2net leaked [-391, 2, 1] memory blocks, sum=-388 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog6P1LxH', '-x'] From python-checkins at python.org Mon Jul 8 17:50:13 2013 From: python-checkins at python.org (ezio.melotti) Date: Mon, 8 Jul 2013 17:50:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_a_couple_o?= =?utf-8?q?f_tests_for_str=2Ecenter_with_non-ASCII_chars=2E?= Message-ID: <3bprhj0hNCz7LjP@mail.python.org> http://hg.python.org/cpython/rev/d249203f423c changeset: 84503:d249203f423c branch: 3.3 parent: 84484:65fce1dad331 user: Ezio Melotti date: Mon Jul 08 17:48:29 2013 +0200 summary: Add a couple of tests for str.center with non-ASCII chars. files: Lib/test/test_unicode.py | 9 +++++++++ 1 files changed, 9 insertions(+), 0 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 @@ -652,6 +652,15 @@ self.assertEqual('?'.swapcase(), 'SS') self.assertEqual('\u1fd2'.swapcase(), '\u0399\u0308\u0300') + def test_center(self): + string_tests.CommonTest.test_center(self) + self.assertEqual('x'.center(2, '\U0010FFFF'), + 'x\U0010FFFF') + self.assertEqual('x'.center(3, '\U0010FFFF'), + '\U0010FFFFx\U0010FFFF') + self.assertEqual('x'.center(4, '\U0010FFFF'), + '\U0010FFFFx\U0010FFFF\U0010FFFF') + def test_contains(self): # Testing Unicode contains method self.assertIn('a', 'abdb') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 17:50:14 2013 From: python-checkins at python.org (ezio.melotti) Date: Mon, 8 Jul 2013 17:50:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_str=2Ecenter_tests_from_3=2E3=2E?= Message-ID: <3bprhk2yTcz7LjP@mail.python.org> http://hg.python.org/cpython/rev/4a0391d61e4c changeset: 84504:4a0391d61e4c parent: 84502:65f2c92ed079 parent: 84503:d249203f423c user: Ezio Melotti date: Mon Jul 08 17:49:59 2013 +0200 summary: Merge str.center tests from 3.3. files: Lib/test/test_unicode.py | 9 +++++++++ 1 files changed, 9 insertions(+), 0 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 @@ -663,6 +663,15 @@ self.assertEqual('?'.swapcase(), 'SS') self.assertEqual('\u1fd2'.swapcase(), '\u0399\u0308\u0300') + def test_center(self): + string_tests.CommonTest.test_center(self) + self.assertEqual('x'.center(2, '\U0010FFFF'), + 'x\U0010FFFF') + self.assertEqual('x'.center(3, '\U0010FFFF'), + '\U0010FFFFx\U0010FFFF') + self.assertEqual('x'.center(4, '\U0010FFFF'), + '\U0010FFFFx\U0010FFFF\U0010FFFF') + def test_contains(self): # Testing Unicode contains method self.assertIn('a', 'abdb') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 17:53:45 2013 From: python-checkins at python.org (ezio.melotti) Date: Mon, 8 Jul 2013 17:53:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4NDAzOiBmaXgg?= =?utf-8?q?an_off-by-one_typo_noticed_by_Xue_Fuqiao=2E?= Message-ID: <3bprmn0Crqz7LjP@mail.python.org> http://hg.python.org/cpython/rev/6f16fa5223cc changeset: 84505:6f16fa5223cc branch: 3.3 parent: 84503:d249203f423c user: Ezio Melotti date: Mon Jul 08 17:52:54 2013 +0200 summary: #18403: fix an off-by-one typo noticed by Xue Fuqiao. files: Doc/tutorial/introduction.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -262,7 +262,7 @@ >>> word[0:2] # characters from position 0 (included) to 2 (excluded) 'Py' - >>> word[2:5] # characters from position 2 (included) to 4 (excluded) + >>> word[2:5] # characters from position 2 (included) to 5 (excluded) 'tho' Note how the start is always included, and the end always excluded. This -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 17:53:46 2013 From: python-checkins at python.org (ezio.melotti) Date: Mon, 8 Jul 2013 17:53:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE4NDAzOiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3bprmp2bYqz7Ljs@mail.python.org> http://hg.python.org/cpython/rev/d41adb657bd4 changeset: 84506:d41adb657bd4 parent: 84504:4a0391d61e4c parent: 84505:6f16fa5223cc user: Ezio Melotti date: Mon Jul 08 17:53:32 2013 +0200 summary: #18403: merge with 3.3. files: Doc/tutorial/introduction.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -262,7 +262,7 @@ >>> word[0:2] # characters from position 0 (included) to 2 (excluded) 'Py' - >>> word[2:5] # characters from position 2 (included) to 4 (excluded) + >>> word[2:5] # characters from position 2 (included) to 5 (excluded) 'tho' Note how the start is always included, and the end always excluded. This -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 22:36:31 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 8 Jul 2013 22:36:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_gcmodule=2Ec=3A_strip_trai?= =?utf-8?q?ling_spaces?= Message-ID: <3bpz336CGdzMwG@mail.python.org> http://hg.python.org/cpython/rev/781be7ad1074 changeset: 84507:781be7ad1074 user: Victor Stinner date: Mon Jul 08 22:15:05 2013 +0200 summary: gcmodule.c: strip trailing spaces files: Modules/gcmodule.c | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -118,7 +118,7 @@ /* NOTE: about untracking of mutable objects. - + Certain types of container cannot participate in a reference cycle, and so do not need to be tracked by the garbage collector. Untracking these objects reduces the cost of garbage collections. However, determining @@ -136,10 +136,10 @@ not survive until garbage collection. It is therefore not worthwhile to untrack eligible tuples at creation time. - Instead, all tuples except the empty tuple are tracked when created. - During garbage collection it is determined whether any surviving tuples - can be untracked. A tuple can be untracked if all of its contents are - already not tracked. Tuples are examined for untracking in all garbage + Instead, all tuples except the empty tuple are tracked when created. + During garbage collection it is determined whether any surviving tuples + can be untracked. A tuple can be untracked if all of its contents are + already not tracked. Tuples are examined for untracking in all garbage collection cycles. It may take more than one cycle to untrack a tuple. Dictionaries containing only immutable objects also do not need to be @@ -152,8 +152,8 @@ The module provides the python function is_tracked(obj), which returns the CURRENT tracking status of the object. Subsequent garbage collections may change the tracking status of the object. - - Untracking of certain containers was introduced in issue #4688, and + + Untracking of certain containers was introduced in issue #4688, and the algorithm was refined in response to issue #14775. */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 22:36:33 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 8 Jul 2013 22:36:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_PyObject?= =?utf-8?q?=5FGC=5FNewVar=28=29_now_raises_SystemError_exception_if_nitems?= Message-ID: <3bpz351MF9z7LjM@mail.python.org> http://hg.python.org/cpython/rev/111c2a070f28 changeset: 84508:111c2a070f28 user: Victor Stinner date: Mon Jul 08 22:17:52 2013 +0200 summary: Issue #18408: PyObject_GC_NewVar() now raises SystemError exception if nitems is negative files: Modules/gcmodule.c | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1689,8 +1689,15 @@ PyVarObject * _PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems) { - const size_t size = _PyObject_VAR_SIZE(tp, nitems); - PyVarObject *op = (PyVarObject *) _PyObject_GC_Malloc(size); + size_t size; + PyVarObject *op; + + if (nitems < 0) { + PyErr_BadInternalCall(); + return NULL; + } + size = _PyObject_VAR_SIZE(tp, nitems); + op = (PyVarObject *) _PyObject_GC_Malloc(size); if (op != NULL) op = PyObject_INIT_VAR(op, tp, nitems); return op; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 22:36:34 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 8 Jul 2013 22:36:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_PyDi?= =?utf-8?q?ct=5FNew=28=29_to_handle_correctly_new=5Fkeys=5Fobject=28=29_fa?= =?utf-8?q?ilure?= Message-ID: <3bpz363dDvz7LjX@mail.python.org> http://hg.python.org/cpython/rev/ba766323b53a changeset: 84509:ba766323b53a user: Victor Stinner date: Mon Jul 08 22:19:20 2013 +0200 summary: Issue #18408: Fix PyDict_New() to handle correctly new_keys_object() failure (MemoryError). files: Objects/dictobject.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -389,6 +389,7 @@ new_dict(PyDictKeysObject *keys, PyObject **values) { PyDictObject *mp; + assert(keys != NULL); if (numfree) { mp = free_list[--numfree]; assert (mp != NULL); @@ -431,7 +432,10 @@ PyObject * PyDict_New(void) { - return new_dict(new_keys_object(PyDict_MINSIZE_COMBINED), NULL); + PyDictKeysObject *keys = new_keys_object(PyDict_MINSIZE_COMBINED); + if (keys == NULL) + return NULL; + return new_dict(keys, NULL); } /* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 22:36:35 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 8 Jul 2013 22:36:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_list?= =?utf-8?q?=2Epop=28=29_to_handle_list=5Fresize=28=29_failure_=28MemoryErr?= =?utf-8?q?or=29=2E?= Message-ID: <3bpz375nQNz7LkW@mail.python.org> http://hg.python.org/cpython/rev/68887e177dd4 changeset: 84510:68887e177dd4 user: Victor Stinner date: Mon Jul 08 22:20:44 2013 +0200 summary: Issue #18408: Fix list.pop() to handle list_resize() failure (MemoryError). files: Objects/listobject.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -925,8 +925,10 @@ v = self->ob_item[i]; if (i == Py_SIZE(self) - 1) { status = list_resize(self, Py_SIZE(self) - 1); - assert(status >= 0); - return v; /* and v now owns the reference the list had */ + if (status >= 0) + return v; /* and v now owns the reference the list had */ + else + return NULL; } Py_INCREF(v); status = list_ass_slice(self, i, i+1, (PyObject *)NULL); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 22:36:37 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 8 Jul 2013 22:36:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_mars?= =?utf-8?q?hal_reader_for_Unicode_strings=3A_handle?= Message-ID: <3bpz390pgbz7LkZ@mail.python.org> http://hg.python.org/cpython/rev/697d722d97f9 changeset: 84511:697d722d97f9 user: Victor Stinner date: Mon Jul 08 22:23:32 2013 +0200 summary: Issue #18408: Fix marshal reader for Unicode strings: handle PyUnicode_DecodeUTF8() failure (ex: MemoryError). files: Python/marshal.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -998,6 +998,10 @@ else { v = PyUnicode_New(0, 0); } + if (v == NULL) { + retval = NULL; + break; + } if (type == TYPE_INTERNED) PyUnicode_InternInPlace(&v); retval = v; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 22:36:38 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 8 Jul 2013 22:36:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_PyTy?= =?utf-8?q?pe=5FReady=28=29_and_type=2E=5F=5Fbases=5F=5F_setter_to_handle?= Message-ID: <3bpz3B36DFz7Lkf@mail.python.org> http://hg.python.org/cpython/rev/de1473f4503b changeset: 84512:de1473f4503b user: Victor Stinner date: Mon Jul 08 22:25:48 2013 +0200 summary: Issue #18408: Fix PyType_Ready() and type.__bases__ setter to handle PyWeakref_NewRef() failure (ex: MemoryError). files: Objects/typeobject.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4329,6 +4329,8 @@ } assert(PyList_Check(list)); newobj = PyWeakref_NewRef((PyObject *)type, NULL); + if (newobj == NULL) + return -1; i = PyList_GET_SIZE(list); while (--i >= 0) { ref = PyList_GET_ITEM(list, i); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 22:36:39 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 8 Jul 2013 22:36:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_call?= =?utf-8?q?=5Ffunction=28=29_of_ceval=2Ec_to_handle_PyTuple=5FNew=28=29_fa?= =?utf-8?q?ilure?= Message-ID: <3bpz3C5NYyz7Ljx@mail.python.org> http://hg.python.org/cpython/rev/f4311870e329 changeset: 84513:f4311870e329 user: Victor Stinner date: Mon Jul 08 22:27:42 2013 +0200 summary: Issue #18408: Fix call_function() of ceval.c to handle PyTuple_New() failure (in load_args()), ex: MemoryError. files: Python/ceval.c | 13 +++++++++---- 1 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4171,10 +4171,15 @@ else { PyObject *callargs; callargs = load_args(pp_stack, na); - READ_TIMESTAMP(*pintr0); - C_TRACE(x, PyCFunction_Call(func,callargs,NULL)); - READ_TIMESTAMP(*pintr1); - Py_XDECREF(callargs); + if (callargs != NULL) { + READ_TIMESTAMP(*pintr0); + C_TRACE(x, PyCFunction_Call(func,callargs,NULL)); + READ_TIMESTAMP(*pintr1); + Py_XDECREF(callargs); + } + else { + x = NULL; + } } } else { if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 22:36:41 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 8 Jul 2013 22:36:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_fix_indentation?= Message-ID: <3bpz3F0S2vz7Ljx@mail.python.org> http://hg.python.org/cpython/rev/890496c5a4d6 changeset: 84514:890496c5a4d6 user: Victor Stinner date: Mon Jul 08 22:28:27 2013 +0200 summary: fix indentation files: Modules/cjkcodecs/multibytecodec.c | 26 +++++++++--------- 1 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -1275,19 +1275,19 @@ if (PyBytes_GET_SIZE(cres) > PY_SSIZE_T_MAX - self->pendingsize) { PyErr_NoMemory(); goto errorexit; - } - rsize = PyBytes_GET_SIZE(cres) + self->pendingsize; - ctr = PyBytes_FromStringAndSize(NULL, rsize); - if (ctr == NULL) - goto errorexit; - ctrdata = PyBytes_AS_STRING(ctr); - memcpy(ctrdata, self->pending, self->pendingsize); - memcpy(ctrdata + self->pendingsize, - PyBytes_AS_STRING(cres), - PyBytes_GET_SIZE(cres)); - Py_DECREF(cres); - cres = ctr; - self->pendingsize = 0; + } + rsize = PyBytes_GET_SIZE(cres) + self->pendingsize; + ctr = PyBytes_FromStringAndSize(NULL, rsize); + if (ctr == NULL) + goto errorexit; + ctrdata = PyBytes_AS_STRING(ctr); + memcpy(ctrdata, self->pending, self->pendingsize); + memcpy(ctrdata + self->pendingsize, + PyBytes_AS_STRING(cres), + PyBytes_GET_SIZE(cres)); + Py_DECREF(cres); + cres = ctr; + self->pendingsize = 0; } rsize = PyBytes_GET_SIZE(cres); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 22:36:42 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 8 Jul 2013 22:36:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_=5FP?= =?utf-8?q?yUnicodeWriter=5FFinish=28=29=3A_clear_writer-=3Ebuffer=2C?= Message-ID: <3bpz3G2ykVz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/df8b40593a08 changeset: 84515:df8b40593a08 user: Victor Stinner date: Mon Jul 08 22:29:55 2013 +0200 summary: Issue #18408: Fix _PyUnicodeWriter_Finish(): clear writer->buffer, so _PyUnicodeWriter_Dealloc() can be called on the writer after finish. files: Objects/unicodeobject.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13157,6 +13157,7 @@ PyObject * _PyUnicodeWriter_Finish(_PyUnicodeWriter *writer) { + PyObject *str; if (writer->pos == 0) { Py_XDECREF(writer->buffer); _Py_RETURN_UNICODE_EMPTY(); @@ -13174,8 +13175,10 @@ } writer->buffer = newbuffer; } - assert(_PyUnicode_CheckConsistency(writer->buffer, 1)); - return unicode_result_ready(writer->buffer); + str = writer->buffer; + writer->buffer = NULL; + assert(_PyUnicode_CheckConsistency(str, 1)); + return unicode_result_ready(str); } void -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 8 23:33:54 2013 From: python-checkins at python.org (ned.deily) Date: Mon, 8 Jul 2013 23:33:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Avoid_spurious_non-fatal_i?= =?utf-8?q?nstall_errors_for_OS_X_frameworks=3A?= Message-ID: <3bq0KG2wngzQkJ@mail.python.org> http://hg.python.org/cpython/rev/c505ece63c80 changeset: 84516:c505ece63c80 user: Ned Deily date: Mon Jul 08 14:33:03 2013 -0700 summary: Avoid spurious non-fatal install errors for OS X frameworks: for a framework install, the python shared library is installed in the frameworkinstallstructure target, not in altbininstall. files: Makefile.pre.in | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -945,7 +945,7 @@ fi; \ (cd $(DESTDIR)$(BINDIR); $(LN) python$(LDVERSION)$(EXE) python$(VERSION)$(EXE)); \ fi - if test -f $(LDLIBRARY); then \ + if test -f $(LDLIBRARY) && test "$(PYTHONFRAMEWORKDIR)" = "no-framework" ; then \ if test -n "$(DLLLIBRARY)" ; then \ $(INSTALL_SHARED) $(DLLLIBRARY) $(DESTDIR)$(BINDIR); \ else \ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 00:53:47 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 9 Jul 2013 00:53:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_Conv?= =?utf-8?q?Param=28=29_of_the_ctypes_module_to_handle_paramfunc_failure?= Message-ID: <3bq25R4zdhz7LkP@mail.python.org> http://hg.python.org/cpython/rev/ba79f6a86300 changeset: 84517:ba79f6a86300 user: Victor Stinner date: Tue Jul 09 00:27:12 2013 +0200 summary: Issue #18408: Fix ConvParam() of the ctypes module to handle paramfunc failure (MemoryError). files: Modules/_ctypes/callproc.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -620,6 +620,8 @@ assert(dict->paramfunc); /* If it has an stgdict, it is a CDataObject */ carg = dict->paramfunc((CDataObject *)obj); + if (carg == NULL) + return -1; pa->ffi_type = carg->pffi_type; memcpy(&pa->value, &carg->value, sizeof(pa->value)); pa->keep = (PyObject *)carg; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 00:53:49 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 9 Jul 2013 00:53:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_zlib?= =?utf-8?q?=2Ecompressobj=28=29_to_handle_PyThread=5Fallocate=5Flock=28=29?= =?utf-8?q?_failure?= Message-ID: <3bq25T05jPz7LkV@mail.python.org> http://hg.python.org/cpython/rev/2ef2edfd1a4c changeset: 84518:2ef2edfd1a4c user: Victor Stinner date: Tue Jul 09 00:29:03 2013 +0200 summary: Issue #18408: Fix zlib.compressobj() to handle PyThread_allocate_lock() failure (MemoryError). files: Modules/zlibmodule.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -132,6 +132,10 @@ } #ifdef WITH_THREAD self->lock = PyThread_allocate_lock(); + if (self->lock == NULL) { + PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); + return NULL; + } #endif return self; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 00:53:50 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 9 Jul 2013 00:53:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_PyCo?= =?utf-8?q?de=5FOptimize=28=29=3A_raise_a_MemoryError_on_memory_allocation?= Message-ID: <3bq25V29Fjz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/a45407fa4a5b changeset: 84519:a45407fa4a5b user: Victor Stinner date: Tue Jul 09 00:32:04 2013 +0200 summary: Issue #18408: Fix PyCode_Optimize(): raise a MemoryError on memory allocation failure. files: Python/peephole.c | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -381,8 +381,10 @@ /* Make a modifiable copy of the code string */ codestr = (unsigned char *)PyMem_Malloc(codelen); - if (codestr == NULL) + if (codestr == NULL) { + PyErr_NoMemory(); goto exitError; + } codestr = (unsigned char *)memcpy(codestr, PyBytes_AS_STRING(code), codelen); @@ -396,8 +398,10 @@ /* Mapping to new jump targets after NOPs are removed */ addrmap = (int *)PyMem_Malloc(codelen * sizeof(int)); - if (addrmap == NULL) + if (addrmap == NULL) { + PyErr_NoMemory(); goto exitError; + } blocks = markblocks(codestr, codelen); if (blocks == NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 00:53:51 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 9 Jul 2013 00:53:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_usag?= =?utf-8?q?e_of_=5FPyBytes=5FResize=28=29?= Message-ID: <3bq25W5TRHz7LkB@mail.python.org> http://hg.python.org/cpython/rev/ed0c9d77e179 changeset: 84520:ed0c9d77e179 user: Victor Stinner date: Tue Jul 09 00:35:22 2013 +0200 summary: Issue #18408: Fix usage of _PyBytes_Resize() _PyBytes_Resize(&v, new_size) sets v to NULL on error, so v cannot be used anymore. Replace "Py_DECREF(v); v = NULL;" with "Py_CLEAR(v);". files: Modules/binascii.c | 23 ++++++++--------------- Modules/zlibmodule.c | 24 ++++++++---------------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -361,8 +361,7 @@ if (_PyBytes_Resize(&rv, (ascii_data - (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { - Py_DECREF(rv); - rv = NULL; + Py_CLEAR(rv); } PyBuffer_Release(&pbin); return rv; @@ -491,8 +490,7 @@ */ if (bin_len > 0) { if (_PyBytes_Resize(&rv, bin_len) < 0) { - Py_DECREF(rv); - rv = NULL; + Py_CLEAR(rv); } } else { @@ -563,8 +561,7 @@ if (_PyBytes_Resize(&rv, (ascii_data - (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { - Py_DECREF(rv); - rv = NULL; + Py_CLEAR(rv); } PyBuffer_Release(&pbuf); return rv; @@ -642,8 +639,7 @@ if (_PyBytes_Resize(&rv, (bin_data - (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { - Py_DECREF(rv); - rv = NULL; + Py_CLEAR(rv); } if (rv) { PyObject *rrv = Py_BuildValue("Oi", rv, done); @@ -713,8 +709,7 @@ if (_PyBytes_Resize(&rv, (out_data - (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { - Py_DECREF(rv); - rv = NULL; + Py_CLEAR(rv); } PyBuffer_Release(&pbuf); return rv; @@ -770,8 +765,7 @@ if (_PyBytes_Resize(&rv, (ascii_data - (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { - Py_DECREF(rv); - rv = NULL; + Py_CLEAR(rv); } PyBuffer_Release(&pbin); return rv; @@ -834,7 +828,7 @@ if ( --out_len_left < 0 ) { \ if ( out_len > PY_SSIZE_T_MAX / 2) return PyErr_NoMemory(); \ if (_PyBytes_Resize(&rv, 2*out_len) < 0) \ - { Py_DECREF(rv); PyBuffer_Release(&pin); return NULL; } \ + { Py_XDECREF(rv); PyBuffer_Release(&pin); return NULL; } \ out_data = (unsigned char *)PyBytes_AS_STRING(rv) \ + out_len; \ out_len_left = out_len-1; \ @@ -887,8 +881,7 @@ if (_PyBytes_Resize(&rv, (out_data - (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { - Py_DECREF(rv); - rv = NULL; + Py_CLEAR(rv); } PyBuffer_Release(&pin); return rv; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -549,8 +549,7 @@ so extend the output buffer and try again */ while (err == Z_OK && self->zst.avail_out == 0) { if (_PyBytes_Resize(&RetVal, length << 1) < 0) { - Py_DECREF(RetVal); - RetVal = NULL; + Py_CLEAR(RetVal); goto error; } self->zst.next_out = @@ -574,8 +573,7 @@ goto error; } if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) { - Py_DECREF(RetVal); - RetVal = NULL; + Py_CLEAR(RetVal); } error: @@ -722,8 +720,7 @@ length = max_length; if (_PyBytes_Resize(&RetVal, length) < 0) { - Py_DECREF(RetVal); - RetVal = NULL; + Py_CLEAR(RetVal); goto error; } self->zst.next_out = @@ -757,8 +754,7 @@ } if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) { - Py_DECREF(RetVal); - RetVal = NULL; + Py_CLEAR(RetVal); } error: @@ -811,8 +807,7 @@ so extend the output buffer and try again */ while (err == Z_OK && self->zst.avail_out == 0) { if (_PyBytes_Resize(&RetVal, length << 1) < 0) { - Py_DECREF(RetVal); - RetVal = NULL; + Py_CLEAR(RetVal); goto error; } self->zst.next_out = @@ -851,8 +846,7 @@ } if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) { - Py_DECREF(RetVal); - RetVal = NULL; + Py_CLEAR(RetVal); } error: @@ -1012,8 +1006,7 @@ so extend the output buffer and try again */ while ((err == Z_OK || err == Z_BUF_ERROR) && self->zst.avail_out == 0) { if (_PyBytes_Resize(&retval, length << 1) < 0) { - Py_DECREF(retval); - retval = NULL; + Py_CLEAR(retval); goto error; } self->zst.next_out = (Byte *)PyBytes_AS_STRING(retval) + length; @@ -1045,8 +1038,7 @@ } if (_PyBytes_Resize(&retval, self->zst.total_out - start_total_out) < 0) { - Py_DECREF(retval); - retval = NULL; + Py_CLEAR(retval); } error: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 00:53:53 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 9 Jul 2013 00:53:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_=5FPyUni?= =?utf-8?q?codeWriter=5FFinish=28=29_now_clears_its_buffer_attribute_in_al?= =?utf-8?q?l?= Message-ID: <3bq25Y0cSQz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/d605c6b8095c changeset: 84521:d605c6b8095c user: Victor Stinner date: Tue Jul 09 00:37:24 2013 +0200 summary: Issue #18408: _PyUnicodeWriter_Finish() now clears its buffer attribute in all cases, so _PyUnicodeWriter_Dealloc() can be called after finish. files: Objects/unicodeobject.c | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13159,18 +13159,21 @@ { PyObject *str; if (writer->pos == 0) { - Py_XDECREF(writer->buffer); + Py_CLEAR(writer->buffer); _Py_RETURN_UNICODE_EMPTY(); } if (writer->readonly) { - assert(PyUnicode_GET_LENGTH(writer->buffer) == writer->pos); - return writer->buffer; + str = writer->buffer; + writer->buffer = NULL; + assert(PyUnicode_GET_LENGTH(str) == writer->pos); + return str; } if (PyUnicode_GET_LENGTH(writer->buffer) != writer->pos) { PyObject *newbuffer; newbuffer = resize_compact(writer->buffer, writer->pos); if (newbuffer == NULL) { Py_DECREF(writer->buffer); + writer->buffer = NULL; return NULL; } writer->buffer = newbuffer; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 00:53:54 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 9 Jul 2013 00:53:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_=5FP?= =?utf-8?q?yMem=5FDebugRealloc=28=29?= Message-ID: <3bq25Z2sKvz7Ljp@mail.python.org> http://hg.python.org/cpython/rev/549d8d3297f2 changeset: 84522:549d8d3297f2 user: Victor Stinner date: Tue Jul 09 00:44:43 2013 +0200 summary: Issue #18408: Fix _PyMem_DebugRealloc() Don't mark old extra memory dead before calling realloc(). realloc() can fail and realloc() must not touch the original buffer on failure. So mark old extra memory dead only on success if the new buffer did not move (has the same address). files: Objects/obmalloc.c | 14 ++++++++------ 1 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -1780,7 +1780,7 @@ _PyMem_DebugRealloc(void *ctx, void *p, size_t nbytes) { debug_alloc_api_t *api = (debug_alloc_api_t *)ctx; - uchar *q = (uchar *)p; + uchar *q = (uchar *)p, *oldq; uchar *tail; size_t total; /* nbytes + 4*SST */ size_t original_nbytes; @@ -1797,24 +1797,26 @@ /* overflow: can't represent total as a size_t */ return NULL; - if (nbytes < original_nbytes) { - /* shrinking: mark old extra memory dead */ - memset(q + nbytes, DEADBYTE, original_nbytes - nbytes + 2*SST); - } - /* Resize and add decorations. We may get a new pointer here, in which * case we didn't get the chance to mark the old memory with DEADBYTE, * but we live with that. */ + oldq = q; q = (uchar *)api->alloc.realloc(api->alloc.ctx, q - 2*SST, total); if (q == NULL) return NULL; + if (q == oldq && nbytes < original_nbytes) { + /* shrinking: mark old extra memory dead */ + memset(q + nbytes, DEADBYTE, original_nbytes - nbytes); + } + write_size_t(q, nbytes); assert(q[SST] == (uchar)api->api_id); for (i = 1; i < SST; ++i) assert(q[SST + i] == FORBIDDENBYTE); q += 2*SST; + tail = q + nbytes; memset(tail, FORBIDDENBYTE, SST); write_size_t(tail + SST, serialno); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 00:53:55 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 9 Jul 2013 00:53:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_sele?= =?utf-8?q?ct=2Eselect=28=29_to_handle_PyList=5FNew=28=29_failure_=28Memor?= =?utf-8?q?yError=29?= Message-ID: <3bq25b51znz7Ljh@mail.python.org> http://hg.python.org/cpython/rev/c91e7f707562 changeset: 84523:c91e7f707562 user: Victor Stinner date: Tue Jul 09 00:49:03 2013 +0200 summary: Issue #18408: Fix select.select() to handle PyList_New() failure (MemoryError) in set2list() files: Modules/selectmodule.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -299,9 +299,9 @@ else ret = PyTuple_Pack(3, ifdlist, ofdlist, efdlist); - Py_DECREF(ifdlist); - Py_DECREF(ofdlist); - Py_DECREF(efdlist); + Py_XDECREF(ifdlist); + Py_XDECREF(ofdlist); + Py_XDECREF(efdlist); } finally: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 04:29:44 2013 From: python-checkins at python.org (richard.jones) Date: Tue, 9 Jul 2013 04:29:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_remove_setuptools_note=3B_set?= =?utf-8?q?uptools_will_now_be_installed?= Message-ID: <3bq6tc5TkJz7Ljk@mail.python.org> http://hg.python.org/peps/rev/11458f6dc9f7 changeset: 4986:11458f6dc9f7 parent: 4924:0a051a14592b user: Richard Jones date: Tue Jul 09 11:20:06 2013 +1000 summary: remove setuptools note; setuptools will now be installed mention bootstrapping target and command-line options mention python 2.6+ bootstrap possibility files: pep-0439.txt | 102 ++++++++++++++++++-------------------- 1 files changed, 49 insertions(+), 53 deletions(-) diff --git a/pep-0439.txt b/pep-0439.txt --- a/pep-0439.txt +++ b/pep-0439.txt @@ -54,9 +54,12 @@ Proposal ======== -This proposal affects three components of packaging: `the pip bootstrap`_, -`setuptools`_ and, thanks to easier package installation, `modifications to -publishing packages`_. +This proposal affects two components of packaging: `the pip bootstrap`_ and, +thanks to easier package installation, `modifications to publishing +packages`_. + +The core of this proposal is that the user experience of using pip should not +require the user to install pip. The pip bootstrap @@ -65,9 +68,11 @@ The Python installation includes an executable called "pip3" (see PEP 394 for naming rationale etc.) that attempts to import pip machinery. If it can then the pip command proceeds as normal. If it cannot it will bootstrap pip by -downloading the pip implementation wheel file. Once installed, the pip -command proceeds as normal. Once the bootstrap process is complete the "pip3" -command is no longer the bootstrap but rather the full pip command. +downloading the pip implementation and setuptools wheel files. Hereafter the +installation of the "pip implementation" will imply installation of +setuptools. Once installed, the pip command proceeds as normal. Once the +bootstrap process is complete the "pip3" command is no longer the bootstrap +but rather the full pip command. A boostrap is used in the place of a the full pip code so that we don't have to bundle pip and also pip is upgradeable outside of the regular Python @@ -89,15 +94,16 @@ 2. The user will invoke a pip command, typically "pip3 install ", for example "pip3 install Django". 3. The boostrap script will attempt to import the pip implementation. - If this succeeds, the pip command is processed normally. + If this succeeds, the pip command is processed normally. Stop. 4. On failing to import the pip implementation the bootstrap notifies - the user that it is "upgrading pip" and contacts PyPI to obtain the - latest download wheel file (see PEP 427.) -5. Upon downloading the file it is installed using the distlib - installation machinery for wheel packages. Upon completing the - installation the user is notified that "pip3 has been upgraded." - TODO how is it verified? -6. The pip tool may now import the pip implementation and continues to + the user that it needs to "install pip". It will ask the user whether it + should install pip as a system-wide site-packages or as a user-only + package. This choice will also be present as a command-line option to pip + so non-interactive use is possible. +5. The bootstrap will and contact PyPI to obtain the latest download wheel + file (see PEP 427.) +6. Upon downloading the file it is installed using "python setup.py install". +7. The pip tool may now import the pip implementation and continues to process the requested user command normally. Users may be running in an environment which cannot access the public @@ -109,7 +115,7 @@ additional locations to discover packages and attempting to download the package from those locations. 2. If the package is not found there then we attempt to donwload it - using the standard "https://pypi.python.org/pypi/simple/pip" index. + using the standard "https://pypi.python.org/simple/pip/" index. 3. If that also fails, for any reason, we indicate to the user the operation we were attempting, the reason for failure (if we know it) and display further instructions for downloading and installing @@ -118,52 +124,33 @@ Some users may have no Internet access suitable for fetching the pip implementation file. Manual installation of the pip implementation will be supported through the manual download of the wheel file and "pip3 install -". This installation - since it uses only the bootstrap -code - will not perform standard pip installation steps of saving the file to -a cache directory or updating any local database of installed files. +". -The download of the pip implementation install file should be performed -securely. The transport from pypi.python.org will be done over HTTPS but the CA -certificate check will most likely not be performed, and therefore the download -would still be vulnerable to active MITM attacks. To mitigate this -risk we will use the embedded signature support in the wheel format to validate -the downloaded file. +The download of the pip implementation install file will be performed +securely. The transport from pypi.python.org will be done over HTTPS with the +CA certificate check performed (see PEP XXXX). Beyond those arguments controlling index location and download options, the "pip3" boostrap command may support further standard pip options for verbosity, quietness and logging. +The "pip3" command will support two new command-line options that are used +in the boostrapping, and otherwise ignored. They control where the pip +implementation is installed: + +--bootstrap + Install to the user's packages directory. The name of this option is chosen + to promote it as the preferred installation option. + +--bootstrap-to-system + Install to the system site-packages directory. + +These command-line options will also need to be implemented, but otherwise +ignored, in the pip implementation. + The "--no-install" option to the "pip3" command will not affect the bootstrapping process. -setuptools ----------- - -The deprecation of requiring setuptools for installation is an existing goal of -the packaging comminity (TODO ref needed). Currently pip depends upon setuptools -functionality, and it is installed by the current pip boostrap. This PEP does -not propose installing setuptools during the new bootstrap. - -It is intended that before Python 3.4 is shipped the functionlity required by -pip will be present in Python's standard library as the distlib module, and that -pip would be modified to use that functionality when present. TODO PEP reference -for distlib - -Many existing "setup.py" files require setuptools to be installed (because one -of the first things they do is import setuptools). It is intended that pip's -behaviour will be either: - -1. If setuptools is not present it can only install from wheel files and - sdists with 2.0+ metadata, or -2. If setuptools is present it can also install from sdists with legacy - metadata and eggs - -By default, installing setuptools when necessary should be automatic so that -users are not inconvenienced, but advanced users should be able to ask that it -instead be treated as an error if no wheel is available to satisfy an -installation request or dependency (so they don't inadvertently install -setuptools on their production systems if they don't want to). - Modifications to publishing packages ------------------------------------ @@ -189,7 +176,16 @@ ============== The changes to pip required by this PEP are being tracked in that project's -issue tracker [2]_ +issue tracker [2]_. Most notably, the addition of --bootstrap and --bootstrap- +to-system to the pip command-line. + +The required code for this implementation is the "pip3" command described +above. The additional pypublish can be developed outside of the scope of this +PEP's work. + +Finally, it would be desirable that "pip3" be ported to Python 2.6+ to allow +the single command to replace all existing pip/setuptools/distribute and +possibly virtualenv bootstrap scripts. Risks -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jul 9 04:29:46 2013 From: python-checkins at python.org (richard.jones) Date: Tue, 9 Jul 2013 04:29:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_mention_having_pip_default_to?= =?utf-8?q?_--user_when_itself_installed_in_=7E/=2Elocal?= Message-ID: <3bq6tf0PM5z7Lk8@mail.python.org> http://hg.python.org/peps/rev/08a91307085f changeset: 4987:08a91307085f user: Richard Jones date: Tue Jul 09 12:23:12 2013 +1000 summary: mention having pip default to --user when itself installed in ~/.local remove consideration of support for unnecessary installation options files: pep-0439.txt | 22 ++++++++-------------- 1 files changed, 8 insertions(+), 14 deletions(-) diff --git a/pep-0439.txt b/pep-0439.txt --- a/pep-0439.txt +++ b/pep-0439.txt @@ -109,22 +109,13 @@ Users may be running in an environment which cannot access the public Internet and are relying solely on a local package repository. They would use the "-i" (Base URL of Python Package Index) argument to the -"pip3 install" command. This use case will be handled by: - -1. Recognising the command-line arguments that specify alternative or - additional locations to discover packages and attempting to - download the package from those locations. -2. If the package is not found there then we attempt to donwload it - using the standard "https://pypi.python.org/simple/pip/" index. -3. If that also fails, for any reason, we indicate to the user the - operation we were attempting, the reason for failure (if we know - it) and display further instructions for downloading and installing - the file manually. +"pip3 install" command. This simply overrides the default index URL pointing +to PyPI. Some users may have no Internet access suitable for fetching the pip -implementation file. Manual installation of the pip implementation will be -supported through the manual download of the wheel file and "pip3 install -". +implementation file. These users can manually download and install the +setuptools and pip tar files. Adding specific support for this use-case is +unnecessary. The download of the pip implementation install file will be performed securely. The transport from pypi.python.org will be done over HTTPS with the @@ -148,6 +139,9 @@ These command-line options will also need to be implemented, but otherwise ignored, in the pip implementation. +Consideration should be given to defaulting pip to install packages to the +user's packages directory if pip is installed in that location. + The "--no-install" option to the "pip3" command will not affect the bootstrapping process. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jul 9 04:29:48 2013 From: python-checkins at python.org (richard.jones) Date: Tue, 9 Jul 2013 04:29:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps_=28merge_default_-=3E_default=29?= =?utf-8?q?=3A_merge?= Message-ID: <3bq6th2sx6z7Lkv@mail.python.org> http://hg.python.org/peps/rev/43d441b2b2ea changeset: 4988:43d441b2b2ea parent: 4987:08a91307085f parent: 4985:e91b098137c5 user: Richard Jones date: Tue Jul 09 12:29:13 2013 +1000 summary: merge files: pep-0008.txt | 18 +- pep-0315.txt | 23 +- pep-0426.txt | 1999 ++++++++++++++-------- pep-0426/pymeta-schema.json | 249 ++ pep-0435.txt | 6 +- pep-0440.txt | 325 ++- pep-0442.txt | 7 +- pep-0443.txt | 75 +- pep-0445.txt | 773 ++++++++ pep-0446.txt | 242 ++ 10 files changed, 2759 insertions(+), 958 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -158,9 +158,21 @@ line continuation inside parentheses, brackets and braces. Long lines can be broken over multiple lines by wrapping expressions in parentheses. These should be used in preference to using a backslash -for line continuation. Make sure to indent the continued line -appropriately. The preferred place to break around a binary operator -is *after* the operator, not before it. Some examples:: +for line continuation. + +Backslashes may still be appropriate at times. For example, long, +multiple ``with``-statements cannot use implicit continuation, so +backslashes are acceptable:: + + with open('/path/to/some/file/you/want/to/read') as file_1, \ + open('/path/to/some/file/being/written', 'w') as file_2: + file_2.write(file_1.read()) + +Another such case is with ``assert`` statements. + +Make sure to indent the continued line appropriately. The preferred +place to break around a binary operator is *after* the operator, not +before it. Some examples:: class Rectangle(Blob): diff --git a/pep-0315.txt b/pep-0315.txt --- a/pep-0315.txt +++ b/pep-0315.txt @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Raymond Hettinger W Isaac Carroll -Status: Deferred +Status: Rejected Type: Standards Track Content-Type: text/plain Created: 25-Apr-2003 @@ -21,19 +21,32 @@ Notice - Deferred; see + Rejected; see + http://mail.python.org/pipermail/python-ideas/2013-June/021610.html + + This PEP has been deferred since 2006; see http://mail.python.org/pipermail/python-dev/2006-February/060718.html Subsequent efforts to revive the PEP in April 2009 did not meet with success because no syntax emerged that could - compete with a while-True and an inner if-break. + compete with the following form: - A syntax was found for a basic do-while loop but it found - had little support because the condition was at the top: + while True: + + if not : + break + + + A syntax alternative to the one proposed in the PEP was found for + a basic do-while loop but it gained little support because the + condition was at the top: do ... while : + Users of the language are advised to use the while-True form with + an inner if-break when a do-while loop would have been appropriate. + Motivation diff --git a/pep-0426.txt b/pep-0426.txt --- a/pep-0426.txt +++ b/pep-0426.txt @@ -12,7 +12,8 @@ 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, 27-May-2013 +Post-History: 14 Nov 2012, 5 Feb 2013, 7 Feb 2013, 9 Feb 2013, + 27 May 2013, 20 Jun 2013, 23 Jun 2013 Replaces: 345 @@ -21,8 +22,7 @@ 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. +and their semantics and usage. This document specifies version 2.0 of the metadata format. Version 1.0 is specified in PEP 241. @@ -42,7 +42,9 @@ "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. + JSON-based rewrite has taken shape. Daniel and Donald have also been + vetting the proposal as we go to ensure it is practical to implement for + both clients and index servers. Metadata 2.0 represents a major upgrade to the Python packaging ecosystem, and attempts to incorporate experience gained over the 15 years(!) since @@ -63,8 +65,7 @@ * 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 linking scheme to better support runtime selection of dependencies * a new static config PEP to standardise metadata generation and creation of sdists * PEP 439, covering a bootstrapping mechanism for ``pip`` @@ -83,138 +84,241 @@ "rationale" section at the end of the document, as it would otherwise be an irrelevant distraction for future readers. - -Definitions -=========== +Purpose +======= + +The purpose of this PEP is to define a common metadata interchange format +for communication between software publication tools and software integration +tools in the Python ecosystem. One key aim is to support full dependency +analysis in that ecosystem without requiring the execution of arbitrary +Python code by those doing the analysis. Another aim is to encourage good +software distribution practices by default, while continuing to support the +current practices of almost all existing users of the Python Package Index +(both publishers and integrators). + +The design draws on the Python community's 15 years of experience with +distutils based software distribution, and incorporates ideas and concepts +from other distribution systems, including Python's setuptools, pip and +other projects, Ruby's gems, Perl's CPAN, Node.js's npm, PHP's composer +and Linux packaging systems such as RPM and APT. + + +Development, Distribution and Deployment of Python Software +=========================================================== + +The metadata design in this PEP is based on a particular conceptual model +of the software development and distribution process. This model consists of +the following phases: + +* Software development: this phase involves working with a source checkout + for a particular application to add features and fix bugs. It is + expected that developers in this phase will need to be able to build the + software, run the software's automated test suite, run project specific + utility scripts and publish the software. + +* Software publication: this phase involves taking the developed software + and making it available for use by software integrators. This includes + creating the descriptive metadata defined in this PEP, as well making the + software available (typically by uploading it to an index server). + +* Software integration: this phase involves taking published software + components and combining them into a coherent, integrated system. This + may be done directly using Python specific cross-platform tools, or it may + be handled through conversion to development language neutral platform + specific packaging systems. + +* Software deployment: this phase involves taking integrated software + components and deploying them on to the target system where the software + will actually execute. + +The publication and integration phases are collectively referred to as +the distribution phase, and the individual software components distributed +in that phase are referred to as "distributions". + +The exact details of these phases will vary greatly for particular use cases. +Deploying a web application to a public Platform-as-a-Service provider, +publishing a new release of a web framework or scientific library, +creating an integrated Linux distribution or upgrading a custom application +running in a secure enclave are all situations this metadata design should +be able to handle. + +The complexity of the metadata described in this PEP thus arises directly +from the actual complexities associated with software development, +distribution and deployment in a wide range of scenarios. + + +Supporting 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. +"Projects" are software components that are made available for integration. +Projects include Python libraries, frameworks, scripts, plugins, +applications, collections of data or other resources, and various +combinations thereof. Public Python projects are typically registered on +the `Python Package Index`_. + +"Releases" are uniquely identified snapshots of a project. + +"Distributions" are the packaged files which are used to publish +and distribute a release. + +"Source archive" and "VCS checkout" both refer to the raw source code for +a release, prior to creation of an sdist or binary archive. + +An "sdist" is a publication format providing the distribution metadata and +and any source files that are essential to creating a binary archive for +the distribution. Creating a binary archive from an sdist requires that +the appropriate build tools be available on the 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. +cross-platform language, many so-called "binary" archives will contain only +pure Python source code. + +"Contributors" are individuals and organizations that work together to +develop a software component. + +"Publishers" are individuals and organizations that make software components +available for integration (typically by uploading distributions to an +index server) + +"Integrators" are individuals and organizations that incorporate published +distributions as components of an application or larger system. "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. +invoked by integration tools in order to build software distributed as +sdists rather than prebuilt binary archives. "Index servers" are active distribution registries which publish version and dependency metadata and place constraints on the permitted metadata. +"Public index servers" are index servers which allow distribution uploads +from untrusted third parties. The `Python Package Index`_ is a public index +server. + "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. +"Integration tools" are automated tools that consume the metadata and +distribution archives published by an index server or other designated +source, and make use of them in some fashion, such as installing them or +converting them to a platform specific packaging format. + +"Installation tools" are integration tools specifically intended to run on +deployment targets, 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 +publication tools, integration 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. +"Entry points" are a scheme for identifying Python callables or other +objects as strings consisting of a Python module name and a module +attribute name, separated by a colon. For example: ``"test.regrtest:main"``. + +"Distros" is used as the preferred term for Linux distributions, to help +avoid confusion with the Python-specific meaning of the term. + + +Integration and deployment of distributions +------------------------------------------- + +The primary purpose of the distribution metadata is to support integration +and deployment of distributions as part of larger applications and systems. + +Integration and deployment can in turn be broken down into further substeps. + +* Build: the build step is the process of turning a VCS checkout, source + archive or sdist 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). + +* Installation: the installation step involves getting the distribution + and all of its runtime dependencies onto the target system. In this + step, the distribution may already be on the system (when upgrading or + reinstalling) or else it may be a completely new installation. + +* Runtime: this is normal usage of a distribution after it has been + installed on the target system. + +These three steps may all occur directly on the target system. Alternatively +the build step may be separated out by using binary archives provided by the +publisher of the distribution, or by creating the binary archives on a +separate system prior to deployment. + +The published metadata for distributions SHOULD allow integrators, with the +aid of build and integration tools, to: + +* obtain the original source code that was used to create a distribution +* identify and retrieve the dependencies (if any) required to use a + distribution +* identify and retrieve the dependencies (if any) required to build a + distribution from source +* identify and retrieve the dependencies (if any) required to run a + distribution's test suite +* find resources on using and contributing to the project +* access sufficiently rich metadata to support contacting distribution + publishers through appropriate channels, as well as finding distributions + that are relevant to particular problems + + +Development and publication of distributions +-------------------------------------------- + +The secondary purpose of the distribution metadata is to support effective +collaboration amongst software contributors and publishers during the +development phase. + +The published metadata for distributions SHOULD allow contributors +and publishers, with the aid of build and publication tools, to: + +* perform all the same activities needed to effectively integrate and + deploy the distribution +* identify and retrieve the additional dependencies needed to develop and + publish the distribution +* specify the dependencies (if any) required to use the distribution +* specify the dependencies (if any) required to build the distribution + from source +* specify the dependencies (if any) required to run the distribution's + test suite +* specify the additional dependencies (if any) required to develop and + publish the distribution + + +Standard build system +--------------------- + +Both development and integration of distributions relies on the ability to +build extension modules and perform other operations in a distribution +independent manner. + +The current iteration of the metadata relies on the +``distutils``/``setuptools`` commands system to support these necessary +development and integration activities: + +* ``python setup.py dist_info``: generate distribution metadata in place + given a source archive or VCS checkout +* ``python setup.py sdist``: create an sdist from a source archive + or VCS checkout +* ``python setup.py build_ext --inplace``: build extension modules in place + given an sdist, source archive or VCS checkout +* ``python setup.py test``: run the distribution's test suite in place + given an sdist, source archive or VCS checkout +* ``python setup.py bdist_wheel``: create a binary archive from an sdist, + source archive or VCS checkout + +Future iterations of the metadata and associated PEPs may aim to replace +these ``distutils``/``setuptools`` dependent commands with build system +independent entry points. Metadata format @@ -247,14 +351,22 @@ Automated tools MAY automatically derive valid values from other information sources (such as a version control system). +Automated tools, especially public index servers, MAY impose additional +length restrictions on metadata beyond those enumerated in this PEP. Such +limits SHOULD be imposed where necessary to protect the integrity of a +service, based on the available resources and the service provider's +judgment of reasonable metadata capacity requirements. + Metadata files -------------- 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. +files for some use cases. These are files containing UTF-8 encoded JSON +metadata. + +Each metadata file consists of a single serialised mapping, with fields as +described in this PEP. There are three standard locations for these metadata files: @@ -270,21 +382,16 @@ 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. + mandates provision of 2.0+ metadata. Other tools involved in Python distribution may also use this format. -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. +As JSON files are generally awkward to edit by hand, it is RECOMMENDED +that these metadata files be generated by build tools based on other +input formats (such as ``setup.py``) rather than being used directly as +a data input format. Generating the metadata as part of the publication +process also helps to deal with version specific fields (including the +source URL and the version field itself). For backwards compatibility with older installation tools, metadata 2.0 files MAY be distributed alongside legacy metadata. @@ -292,6 +399,10 @@ Index servers MAY allow distributions to be uploaded and installation tools MAY allow distributions to be installed with only legacy metadata. +Automated tools MAY attempt to automatically translate legacy metadata to +the format described in this PEP. Advice for doing so effectively is given +in Appendix A. + Essential dependency resolution metadata ---------------------------------------- @@ -304,13 +415,18 @@ fields: * ``metadata_version`` +* ``generator`` * ``name`` * ``version`` -* ``build_label`` -* ``version_url`` +* ``source_label`` +* ``source_url`` * ``extras`` -* ``requires`` -* ``may_require`` +* ``meta_requires`` +* ``meta_may_require`` +* ``run_requires`` +* ``run_may_require`` +* ``test_requires`` +* ``test_may_require`` * ``build_requires`` * ``build_may_require`` * ``dev_requires`` @@ -320,23 +436,34 @@ * ``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``. +be ``pymeta-dependencies.json``. + + +Included documents +------------------ + +Rather than being incorporated directly into the structured metadata, some +supporting documents are included alongside the metadata file in the +``dist-info`` metadata directory. + +To accommodate the variety of existing naming conventions for these files, +they are explicitly identified in the ``document_names`` field, rather +than expecting index servers and other automated tools to identify them +automatically. + + +Metadata validation +------------------- + +A `jsonschema `__ description of +the distribution metadata is `available +`__. + +This schema does NOT currently handle validation of some of the more complex +string fields (instead treating them as opaque strings). + +Except where otherwise noted, all URL fields in the metadata MUST comply +with RFC 3986. Core metadata @@ -376,6 +503,17 @@ "metadata_version": "2.0" +Generator +--------- + +Name (and optional version) of the program that generated the file, +if any. A manually produced file would omit this field. + +Example:: + + "generator": "setuptools (0.8)" + + Name ---- @@ -391,7 +529,7 @@ * hyphens (``-``) * periods (``.``) -Distributions named MUST start and end with an ASCII letter or digit. +Distribution names MUST start and end with an ASCII letter or digit. Automated tools MUST reject non-compliant names. @@ -399,14 +537,14 @@ 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 +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 +Integration 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 @@ -421,45 +559,6 @@ "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 ------- @@ -469,11 +568,33 @@ variety of flexible version specification mechanisms (see PEP 440 for details). +Version identifiers MUST comply with the format defined in PEP 440. + +Version identifiers MUST be unique within each project. + Example:: "version": "1.0a2" +Summary +------- + +A short summary of what the distribution does. + +This field SHOULD contain fewer than 512 characters and MUST contain fewer +than 2048. + +This field SHOULD NOT contain any line breaks. + +A more complete description SHOULD be included as a separate file in the +sdist for the distribution. See `Document names`_ for details. + +Example:: + + "summary": "A module that is more fiendish than soft cushions." + + Source code metadata ==================== @@ -489,9 +610,13 @@ ------------ 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). - +cannot be used in version specifiers - they are included for information +purposes only. + +Source labels MUST meet the character restrictions defined in PEP 440. + +Source labels MUST be unique within each project and MUST NOT match any +defined version for the project. Examples:: @@ -508,19 +633,23 @@ ---------- 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 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 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 -understand), automated tools SHOULD at least emit a warning and MAY +the distribution can be downloaded. + +Source URLs MUST be unique within each project. 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"``. + +The source URL MUST reference either a source archive or a tag or specific +commit in an online version control system that permits creation of a +suitable VCS checkout. It is intended primarily for integrators that +wish to recreate the distribution from the original source form. + +All source URL references SHOULD specify a secure transport +mechanism (such as ``https``), include an expected hash value in the +URL for verification purposes, or both. If an insecure transport is specified +without any hash information, with hash information that the tool doesn't +understand, or with a selected hash algorithm that the tool considers too +weak to trust, 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 @@ -530,7 +659,7 @@ ``'sha512'``. For source archive references, an expected hash value may be specified by -including a ``=`` as part of the URL +including a ``=`` entry as part of the URL fragment. For version control references, the ``VCS+protocol`` scheme SHOULD be @@ -546,29 +675,6 @@ "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:: - - 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 =============================== @@ -580,74 +686,29 @@ a distribution does not provide them, including failing cleanly when an operation depending on one of these fields is requested. -Summary + +License ------- -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. +A short string summarising the license used for this distribution. + +Note that distributions that provide this field should still specify any +applicable license Trove classifiers in the `Classifiers`_ field. Even +when an appropriate Trove classifier is available, the license summary can +be a good way to specify a particular version of that license, or to +indicate any variations or exception to the license. + +This field SHOULD contain fewer than 512 characters and MUST contain fewer +than 2048. + +This field SHOULD NOT contain any line breaks. + +The full license text SHOULD be included as a separate file in the source +archive for the distribution. See `Document names`_ for details. Example:: - "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 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. - -Example:: - - "description": "The ComfyChair module replaces SoftCushions.\\n\\nUse until lunchtime, but pause for a cup of coffee at eleven." - -.. note:: - - 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" + "license": "GPL version 3, excluding DRM provisions" Keywords @@ -661,40 +722,6 @@ "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:: - - 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 ----------- @@ -704,11 +731,60 @@ Example:: "classifiers": [ - "Development Status :: 4 - Beta", - "Environment :: Console (Text Based)" + "Development Status :: 4 - Beta", + "Environment :: Console (Text Based)", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)" ] +Document names +-------------- + +Filenames for supporting documents included in the distribution's +``dist-info`` metadata directory. + +The following supporting documents can be named: + +* ``description``: a file containing a long description of the distribution +* ``license``: a file with the full text of the distribution's license +* ``changelog``: a file describing changes made to the distribution + +Supporting documents MUST be included directly in the ``dist-info`` +directory. Directory separators are NOT permitted in document names. + +The markup format (if any) for the file is indicated by the file extension. +This allows index servers and other automated tools to render included +text documents correctly and provide feedback on rendering errors, rather +than having to guess the intended format. + +If the filename has no extension, or the extension is not recognised, the +default rendering format MUST be plain text. + +The following markup renderers SHOULD be used for the specified file +extensions: + +* Plain text: ``.txt``, no extension, unknown extension +* reStructured Text: ``.rst`` +* Markdown: ``.md`` +* AsciiDoc: ``.adoc``, ``.asc``, ``.asciidoc`` +* HTML: ``.html``, ``.htm`` + +Automated tools MAY render one or more of the specified formats as plain +text and MAY render other markup formats beyond those listed. + +Automated tools SHOULD NOT make any assumptions regarding the maximum length +of supporting document content, except as necessary to protect the +integrity of a service. + +Example:: + + "document_names": { + "description": "README.rst", + "license": "LICENSE.rst", + "changelog": "NEWS" + } + + Contributor metadata ==================== @@ -726,6 +802,12 @@ If no specific role is stated, the default is ``contributor``. +Email addresses must be in the form ``local-part at domain`` where the +local-part may be up to 64 characters long and the entire email address +contains no more than 254 characters. The formal specification of the +format is in RFC 5322 (sections 3.2.3 and 3.4.1) and RFC 5321, with a more +readable form given in the informational RFC 3696 and the associated errata. + The defined contributor roles are as follows: * ``author``: the original creator of a distribution @@ -734,15 +816,6 @@ * ``contributor``: any other individuals or organizations involved in the creation of the distribution -.. note:: - - 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 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. @@ -789,12 +862,12 @@ Example:: "contributors": [ - {"name": "John C."}, - {"name": "Erik I."}, - {"name": "Terry G."}, - {"name": "Mike P."}, - {"name": "Graeme C."}, - {"name": "Terry J."} + {"name": "John C."}, + {"name": "Erik I."}, + {"name": "Terry G."}, + {"name": "Mike P."}, + {"name": "Graeme C."}, + {"name": "Terry J."} ] @@ -815,34 +888,45 @@ Example:: "project_urls": { - "Documentation": "https://distlib.readthedocs.org" - "Home": "https://bitbucket.org/pypa/distlib" - "Repository": "https://bitbucket.org/pypa/distlib/src" - "Tracker": "https://bitbucket.org/pypa/distlib/issues" + "Documentation": "https://distlib.readthedocs.org" + "Home": "https://bitbucket.org/pypa/distlib" + "Repository": "https://bitbucket.org/pypa/distlib/src" + "Tracker": "https://bitbucket.org/pypa/distlib/issues" } -Dependency metadata -=================== +Semantic dependencies +===================== Dependency metadata allows distributions to make use of functionality provided by other distributions, without needing to bundle copies of those distributions. +Semantic dependencies allow publishers to indicate not only which other +distributions are needed, but also *why* they're needed. This additional +information allows integrators to install just the dependencies they need +for specific activities, making it easier to minimise installation +footprints in constrained environments (regardless of the reasons for +those constraints). + +Distributions may declare five differents kinds of dependency: + +* "Meta" dependencies: subdistributions that are grouped together into a + single larger metadistribution for ease of reference and installation. +* Runtime dependencies: other distributions that are needed to actually use + this distribution (but are not considered subdistributions). +* Test dependencies: other distributions that are needed to run the + automated test suite for this distribution (but are not needed just to + use it). +* Build dependencies: other distributions that are needed to build this + distribution. +* Development dependencies: other distributions that are needed when + working on this distribution (but do not fit into one of the other + dependency categories). + Dependency management is heavily dependent on the version identification and specification scheme defined in PEP 440. -.. note:: - - 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`` 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 indicates "Not applicable for this distribution". @@ -854,10 +938,11 @@ 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). +brackets) and by a version specifier or direct reference (within +parentheses). See `Extras (optional dependencies)`_ for details on extras and PEP 440 -for details on version specifiers. +for details on version specifiers and direct references. 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 @@ -903,13 +988,6 @@ 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 --------------------------------------------------------------- @@ -918,26 +996,34 @@ and development activities identified above, and govern which dependencies should be installed for the specified activities: -* Deployment dependencies: - - * ``distributes`` - * ``requires`` - * ``may_require`` - * Request the ``test`` extra to also install - +* Implied runtime dependencies: + + * ``meta_requires`` + * ``meta_may_require`` + * ``run_requires`` + * ``run_may_require`` + +* Implied build dependencies: + + * ``build_requires`` + * ``build_may_require`` + * If running the distribution's test suite as part of the build process, + request the ``:meta:``, ``:run:`` and ``:test:`` extras to also + install: + + * ``meta_requires`` + * ``meta_may_require`` + * ``run_requires`` + * ``run_may_require`` * ``test_requires`` * ``test_may_require`` -* Build dependencies: - - * ``build_requires`` - * ``build_may_require`` - -* Development dependencies: - - * ``distributes`` - * ``requires`` - * ``may_require`` +* Implied development and publication dependencies: + + * ``meta_requires`` + * ``meta_may_require`` + * ``run_requires`` + * ``run_may_require`` * ``build_requires`` * ``build_may_require`` * ``test_requires`` @@ -945,139 +1031,146 @@ * ``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 -* 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 -or build dependencies. +The notation described in `Extras (optional dependencies)`_ SHOULD be used +to determine exactly what gets installed for various operations. 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 ``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. - - 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. - - -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)"] +See Appendix B for an overview of mapping these dependencies to an RPM +spec file. 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. +conditional dependencies in ``"may_distribute"``, ``"run_may_require"`` and +similar fields. See `Extras (optional dependencies)`_ for details. + +The names of extras MUST abide by the same restrictions as those for +distribution names. 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 +Meta requires +------------- + +An abbreviation of "metadistribution requires". This is a list of +subdistributions that can easily be installed and used together by +depending on this metadistribution. + +In this field, automated tools: + +* MUST allow strict version matching +* MUST NOT allow more permissive version specifiers. +* MAY allow direct references + +Public index servers SHOULD NOT allow the use of direct references in +uploaded distributions. Direct references are intended primarily as a +tool for software integrators rather than publishers. + +Distributions that rely on direct references to platform specific binary +archives SHOULD define appropriate constraints in their +``supports_environments`` field. + +Example:: + + "meta_requires": ["ComfyUpholstery (== 1.0a2)", + "ComfySeatCushion (== 1.0a2)"] + + +Meta may require +---------------- + +An abbreviation of "metadistribution may require". This is a list of +subdistributions that can easily be installed and used together by +depending on this metadistribution, but are not required in all +circumstances. + +Any extras referenced from this field MUST be named in the `Extras`_ field. + +In this field, automated tools: + +* MUST allow strict version matching +* MUST NOT allow more permissive version specifiers. +* MAY allow direct references + +Public index servers SHOULD NOT allow the use of direct references in +uploaded distributions. Direct references are intended primarily as a +tool for software integrators rather than publishers. + +Distributions that rely on direct references to platform specific binary +archives SHOULD defined appropriate constraints in their +``supports_environments`` field. + +Example:: + + "meta_may_require": [ + { + "dependencies": ["CupOfTeaAtEleven (== 1.0a2)"], + "environment": "'linux' in sys.platform" + } + ] + + +Run requires +------------ + +A list of other distributions needed to actually run this distribution. + +Automated tools MUST NOT allow strict version matching clauses or direct +references in this field - if permitted at all, such clauses should appear +in ``meta_requires`` instead. + +Example:: + + "run_requires": ["SciPy", "PasteDeploy", "zope.interface (>3.5.0)"] + + +Run may require +--------------- + +A list of other distributions that may be needed to actually run this +distribution, based on the extras requested and the target deployment environment. 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. +Automated tools MUST NOT allow strict version matching clauses or direct +references in this field - if permitted at all, such clauses should appear +in ``meta_may_require`` instead. Example:: - "may_require": [ - { - "dependencies": ["pywin32 (>1.0)"], - "environment": "sys.platform == 'win32'" - }, - { - "dependencies": ["SoftCushions"], - "extra": "warmup" - } - ] + "run_may_require": [ + { + "dependencies": ["pywin32 (>1.0)"], + "environment": "sys.platform == 'win32'" + }, + { + "dependencies": ["SoftCushions"], + "extra": "warmup" + } + ] + Test requires ------------- 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. - -Automated tools MAY disallow strict version matching clauses and source +for this distribution.. + +Automated tools MAY disallow strict version matching clauses and direct references in this field and SHOULD at least emit a warning for such clauses. +Public index servers SHOULD NOT allow strict version matching clauses or +direct references in this field. + Example:: "test_requires": ["unittest2"] @@ -1087,41 +1180,45 @@ ---------------- 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. +automated tests for this distribution. Any extras referenced from this field MUST be named in the `Extras`_ field. -Automated tools MAY disallow strict version matching clauses and source +Automated tools MAY disallow strict version matching clauses and direct references in this field and SHOULD at least emit a warning for such clauses. +Public index servers SHOULD NOT allow strict version matching clauses or +direct references in this field. + Example:: - "test_may_require": [ - { - "dependencies": ["pywin32 (>1.0)"], - "environment": "sys.platform == 'win32'" - }, - { - "dependencies": ["CompressPadding"], - "extra": "warmup" - } - ] + "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). +(creating a binary archive from an sdist, source archive or VCS checkout). 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 +Automated tools MAY disallow strict version matching clauses and direct references in this field and SHOULD at least emit a warning for such clauses. +Public index servers SHOULD NOT allow strict version matching clauses or +direct references in this field. + Example:: "build_requires": ["setuptools (>= 0.7)"] @@ -1131,8 +1228,8 @@ ----------------- 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. +is built (creating a binary archive from an sdist, source archive or +VCS checkout), 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. @@ -1142,21 +1239,24 @@ Automated tools MAY assume that all extras are implicitly requested when installing build dependencies. -Automated tools MAY disallow strict version matching clauses and source +Automated tools MAY disallow strict version matching clauses and direct references in this field and SHOULD at least emit a warning for such clauses. +Public index servers SHOULD NOT allow strict version matching clauses or +direct references in this field. + Example:: - "build_may_require": [ - { - "dependencies": ["pywin32 (>1.0)"], - "environment": "sys.platform == 'win32'" - }, - { - "dependencies": ["cython"], - "extra": "c-accelerators" - } - ] + "build_may_require": [ + { + "dependencies": ["pywin32 (>1.0)"], + "environment": "sys.platform == 'win32'" + }, + { + "dependencies": ["cython"], + "extra": "c-accelerators" + } + ] Dev requires @@ -1168,17 +1268,16 @@ Additional dependencies that may be listed in this field include: -* tools needed to create a source archive +* tools needed to create an sdist from a source archive or VCS checkout * 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) - -Automated tools MAY disallow strict version matching clauses and source + +Automated tools MAY disallow strict version matching clauses and direct references in this field and SHOULD at least emit a warning for such clauses. +Public index servers SHOULD NOT allow strict version matching clauses or +direct references in this field. + Example:: "dev_requires": ["hgtools", "sphinx (>= 1.0)"] @@ -1199,17 +1298,20 @@ Automated tools MAY assume that all extras are implicitly requested when installing development dependencies. -Automated tools MAY disallow strict version matching clauses and source +Automated tools MAY disallow strict version matching clauses and direct references in this field and SHOULD at least emit a warning for such clauses. +Public index servers SHOULD NOT allow strict version matching clauses or +direct references in this field. + Example:: - "dev_may_require": [ - { - "dependencies": ["pywin32 (>1.0)"], - "environment": "sys.platform == 'win32'" - } - ] + "dev_may_require": [ + { + "dependencies": ["pywin32 (>1.0)"], + "environment": "sys.platform == 'win32'" + } + ] Provides @@ -1231,6 +1333,19 @@ project is able to include a ``"provides": ["distribute"]`` entry to satisfy any projects that require the now obsolete distribution's name. +To avoid malicious hijacking of names, when interpreting metadata retrieved +from a public index server, automated tools MUST prefer the distribution +named in a version specifier over other distributions using that +distribution's name in a ``"provides"`` entry. Index servers MAY drop such +entries from the metadata they republish, but SHOULD NOT refuse to publish +such distributions. + +However, to appropriately handle project forks and mergers, automated tools +MUST accept ``"provides"`` entries that name other distributions when the +entry is retrieved from a local installation database or when there is a +corresponding ``"obsoleted_by"`` entry in the metadata for the named +distribution. + 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 @@ -1291,63 +1406,66 @@ Individual entries are environment markers, as described in `Environment markers`_. -Installation tools SHOULD report an error if supported platforms are +Installation tools SHOULD report an error if supported environments 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:: - +The two main uses of this field are to declare which versions of Python +and which underlying operating systems are supported. + +Examples indicating supported Python versions:: + + # Supports Python 2.6+ + "supports_environments": ["python_version >= '2.6'"] + + # Supports Python 2.6+ (for 2.x) or 3.3+ (for 3.x) + "supports_environments": ["python_version >= '3.3'", + "'3.0' > python_version >= '2.6'"] + +Examples indicating supported operating systems:: + + # Windows only "supports_environments": ["sys_platform == 'win32'"] + + # Anything except Windows "supports_environments": ["sys_platform != 'win32'"] + + # Linux or BSD only "supports_environments": ["'linux' in sys_platform", "'bsd' in sys_platform"] - -.. note:: - - 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: +Example where the supported Python version varies by platform:: + + # The standard library's os module has long supported atomic renaming + # on POSIX systems, but only gained atomic renaming on Windows in Python + # 3.3. A distribution that needs atomic renaming support for reliable + # operation might declare the following supported environments. + "supports_environments": ["python_version >= '2.6' and sys_platform != 'win32'", + "python_version >= '3.3' and sys_platform == 'win32'"] + + +Install hooks +============= + +The ``install_hooks`` field is used to define operations to be +invoked on the distribution in the following situations: * 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" + +Distributions may define handlers for each of these operations as an +"entry point", which is a reference to a Python callable, with the module +name separated from the reference within the module by a colon (``:``). + +Example install hooks:: + + "install_hooks": { + "postinstall": "ComfyChair.install_hooks:postinstall", + "preuininstall": "ComfyChair.install_hooks:preuninstall" } -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: +The currently defined install 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 @@ -1357,18 +1475,15 @@ 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:: + +The required 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 + *previous_meta* is either omitted or ``None`` (indicating a fresh install) or else the distribution metadata for the version that was previously installed (indicating an upgrade or downgrade). """ @@ -1378,30 +1493,65 @@ *current_meta* is the distribution metadata for the version now installed on the current system - *next_meta* is either missing or ``None`` (indicating complete + *next_meta* is either omitted 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). +When install hooks are defined, it is assumed that they MUST be executed +to obtain a properly working installation of the distribution, and to +properly remove the distribution from a system. + +Install hooks SHOULD NOT be used to provide functionality that is +expected to be provided by installation tools (such as rewriting of +shebang lines and generation of executable wrappers for Windows). + +Installation tools MUST ensure the distribution is fully installed, and +available through the import system and installation database when invoking +install hooks. + +Installation tools MUST call install hooks with full metadata, rather than +only the essential dependency resolution metadata. + +The given parameter names are considered part of the hook signature. +Installation tools MUST call install hooks solely with keyword arguments. +Install hook implementations MUST use the given parameter names. + +Installation tools SHOULD invoke install hooks automatically after +installing a distribution from a binary archive. + +When installing from an sdist, source archive or VCS checkout, installation +tools SHOULD create a binary archive using ``setup.py bdist_wheel`` and +then install binary archive normally (including invocation of any install +hooks). Installation tools SHOULD NOT invoke ``setup.py install`` directly. + +Installation tools SHOULD treat an exception thrown by a postinstall hook +as a failure of the installation and revert any other changes made to the +system. + +Installation tools SHOULD treat an exception thrown by a preuninstall hook +as an indication the removal of the distribution should be aborted. + +Installation tools MUST NOT silently ignore install hooks, as failing +to call these hooks may result in a misconfigured installation that fails +unexpectedly at runtime. Installation tools MAY refuse to install +distributions that define install hooks, or require that users +explicitly opt in to permitting the execution of such hooks. + +Install hook implementations MUST NOT make any assumptions regarding the +current working directory when they are invoked, and MUST NOT make +persistent alterations to the working directory or any other process global +state (other than potentially importing additional modules, or other +expected side effects of running the distribution). + +Install hooks have access to the full metadata for the release being +installed, that of the previous/next release (as appropriate), as well as +to all the normal runtime information (such as available imports). Hook +implementations can use this information to perform additional platform +specific installation steps. To check for the presence or absence of +"extras", hook implementations should use the same runtime checks that +would be used during normal operation (such as checking for the availability +of the relevant dependencies). Metadata Extensions @@ -1413,14 +1563,20 @@ in JSON:: "extensions" : { - "chili" : { "type" : "Poblano", "heat" : "Mild" }, - "languages" : [ "French", "Italian", "Hebrew" ] + "chili" : { "type" : "Poblano", "heat" : "Mild" }, + "languages" : [ "French", "Italian", "Hebrew" ] } -To avoid name conflicts, it is recommended that distribution names be used +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. +Metadata extensions allow development tools to record information in the +metadata that may be useful during later phases of distribution. For +example, a build tool could include default build options in a metadata +extension when creating an sdist, and use those when creating the wheel +files later. + Extras (optional dependencies) ============================== @@ -1440,7 +1596,7 @@ "name": "ComfyChair", "extras": ["warmup", "c-accelerators"] - "may_require": [ + "run_may_require": [ { "dependencies": ["SoftCushions"], "extra": "warmup" @@ -1457,15 +1613,32 @@ 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 +Extra specifications MUST allow the following additional syntax: + +* Multiple extras 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. +* The following special extras request processing of the corresponding + lists of dependencies: + + * ``:meta:``: ``meta_requires`` and ``meta_may_require`` + * ``:run:``: ``run_requires`` and ``run_may_require`` + * ``:test:``: ``test_requires`` and ``test_may_require`` + * ``:build:``: ``build_requires`` and ``build_may_require`` + * ``:dev:``: ``dev_requires`` and ``dev_may_require`` + * ``:*:``: process *all* dependency lists + +* The ``*`` character as an extra is a wild card that enables all of the + entries defined in the distribution's ``extras`` field. +* Extras may be explicitly excluded by prefixing their name with a ``-`` + character (this is useful in conjunction with ``*`` to exclude only + particular extras that are definitely not wanted, while enabling all + others). + +* The ``-`` character as an extra specification indicates that the + distribution itself should NOT be installed, and also disables the + normally implied processing of ``:meta:`` and ``:run:`` dependencies + (those may still be requested explicitly using the appropriate extra + specifications). Command line based installation tools SHOULD support this same syntax to allow extras to be requested explicitly. @@ -1473,15 +1646,31 @@ 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]"] +Dependency examples:: + + "run_requires": ["ComfyChair[warmup]"] -> requires ``ComfyChair`` and ``SoftCushions`` at run time - "requires": ["ComfyChair[*]"] + "run_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 + will also pick up any new extras defined in later versions + +Command line examples:: + + pip install ComfyChair + -> installs ComfyChair with applicable :meta: and :run: dependencies + + pip install ComfyChair[*] + -> as above, but also installs all extra dependencies + + pip install ComfyChair[-,:build:,*] + -> installs just the build dependencies with all extras + + pip install ComfyChair[-,:build:,:run:,:meta:,:test:,*] + -> as above, but also installs dependencies needed to run the tests + + pip install ComfyChair[-,:*:,*] + -> installs the full set of development dependencies Environment markers @@ -1504,7 +1693,7 @@ requires PyWin32 both at runtime and buildtime when using Windows:: "name": "ComfyChair", - "may_require": [ + "run_may_require": [ { "dependencies": ["pywin32 (>1.0)"], "environment": "sys.platform == 'win32'" @@ -1539,6 +1728,12 @@ * ``platform_version``: ``platform.version()`` * ``platform_machine``: ``platform.machine()`` * ``platform_python_implementation``: ``platform.python_implementation()`` +* ``implementation_name````: ``sys.implementation.name`` +* ``implementation_version````: see definition below + +If a particular value is not available (such as the ``sys.implementation`` +subattributes in versions of Python prior to 3.3), the corresponding marker +variable MUST be considered equivalent to the empty string. Note that all subexpressions are restricted to strings or one of the marker variable names (which refer to string values), meaning that it is @@ -1548,17 +1743,24 @@ 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:: - - def format_full_version(): - info = sys.version_info +The ``python_full_version`` and ``implementation_version`` marker variables +are derived from ``sys.version_info()`` and ``sys.implementation.version`` +respectively, in accordance with the following algorithm:: + + def format_full_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 + python_full_version = format_full_version(sys.version_info) + implementation_version = format_full_version(sys.implementation.version) + +``python_full_version`` will typically correspond to the leading segment +of ``sys.version()``. + + Updating the metadata specification =================================== @@ -1570,8 +1772,68 @@ defined in a new PEP. -Summary of differences from \PEP 345 -==================================== +Appendix A: Conversion notes for legacy metadata +================================================ + +The reference implementations for converting from legacy metadata to +metadata 2.0 are: + +* the `wheel project `__, which + adds the ``bdist_wheel`` command to ``setuptools`` +* the `Warehouse project `__, which + will eventually be migrated to the Python Packaging Authority as the next + generation Python Package Index implementation +* the `distlib project `__ which is + derived from the core packaging infrastructure created for the + ``distutils2`` project and + +While it is expected that there may be some edge cases where manual +intervention is needed for clean conversion, the specification has been +designed to allow fully automated conversion of almost all projects on +PyPI. + +Metadata conversion (especially on the part of the index server) is a +necessary step to allow installation and analysis tools to start +benefiting from the new metadata format, without having to wait for +developers to upgrade to newer build systems. + + +Appendix B: Mapping dependency declarations to an RPM SPEC file +=============================================================== + + +As an example of mapping this PEP 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 ``meta_requires``, ``run_requires`` and applicable +``meta_may_require`` ``run_may_require`` dependencies would be mapped +to the Requires dependencies for the "example" RPM (a mapping from +environment markers relevant to Linux 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``, ``test_requires``, ``dev_may_require``, and +``test_may_require`` would become Requires dependencies for the +"example-devel" RPM. + +If the project did define any extras, those would likely 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. + + +Appendix C: Summary of differences from \PEP 345 +================================================= * Metadata-Version is now 2.0, with semantics specified for handling version changes @@ -1592,21 +1854,21 @@ * 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 +* Added the source label mechanism as described in PEP 440 + +* Support for different kinds of dependencies * The "Extras" optional dependency mechanism * A well-defined metadata extension mechanism -* Metabuild hook system +* Install 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 + * allow ordered string comparisons and chained comparisons * More flexible system for defining contact points and contributors @@ -1616,9 +1878,11 @@ * Updated obsolescence mechanism -* Added "License URL" field - -* Explicit declaration of description markup format +* Identification of supporting documents in the ``dist-info`` directory: + + * Allows markup formats to be indicated through file extensions + * Standardises the common practice of taking the description from README + * Also supports inclusion of license files and changelogs * With all due respect to Charles Schulz and Peanuts, many of the examples have been updated to be more `thematically appropriate`_ for Python ;) @@ -1667,7 +1931,7 @@ 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 +standard Python data structures for use in the new install hook APIs, or in future extensions to the importer APIs to allow them to provide information for inclusion in the installation database. @@ -1691,33 +1955,47 @@ See PEP 440 for the rationale behind the addition of this field. -Development, build and deployment dependencies ----------------------------------------------- - -The separation of the ``requires``, ``build_requires`` and ``dev_requires`` -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 -over where particular dependencies end up being installed . +Support for different kinds of dependencies +------------------------------------------- + +The separation of the five different kinds of dependency allows a +distribution to indicate whether a dependency is needed specifically to +develop, build, test or use the distribution. + +To allow for metadistributions like PyObjC, while still actively +discouraging overly strict dependency specifications, the separate +``meta`` dependency fields are used to separate out those dependencies +where exact version specifications are appropriate. + +The advantage of having these distinctions supported in the upstream Python +specific metadata is that even if a project doesn't care about these +distinction themselves, they may be more amenable to patches from +downstream redistributors that separate the fields appropriately. Over time, +this should allow much greater control over where and when particular +dependencies end up being installed. + +The names for the dependency fields have been deliberately chosen to avoid +conflicting with the existing terminology in setuptools and previous +versions of the metadata standard. Specifically, the names ``requires``, +``install_requires`` and ``setup_requires`` are not used, which will +hopefully reduce confustion when converting legacy metadata to the new +standard. 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``. +behaviour, and to use the ``*may_require`` fields to indicate when +particular dependencies are needed only to support that behaviour. 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 additions to the extras syntax relative to setuptools are defined to +make it easier to express the various possible combinations of dependencies, +in particular those associated with build systems (with optional support +for running the test suite) and development systems. Support for metadata extensions @@ -1734,21 +2012,39 @@ particular extensions to be provided as optional features. -Support for metabuild hooks +Support for install hooks --------------------------- -The new metabuild system is designed to allow the wheel format to fully -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 -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 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. +The new install hook system is designed to allow the wheel format to fully +replace direct installation on deployment targets, by allowing projects to +explicitly define code that should be executed following installation from +a wheel file. + +This may be something relatively simple, like the `two line +refresh `__ +of the Twisted plugin caches that the Twisted developers recommend for +any project that provides Twisted plugins, to more complex platform +dependent behaviour, potentially in conjunction with appropriate +metadata extensions and ``supports_environments`` entries. + +For example, upstream declaration of external dependencies for various +Linux distributions in a distribution neutral format may be supported by +defining an appropriate metadata extension that is read by a postinstall +hook and converted into an appropriate invocation of the system package +manager. Other operations (such as registering COM DLLs on Windows, +registering services for automatic startup on any platform, or altering +firewall settings) may need to be undertaken with elevated privileges, +meaning they cannot be deferred to implicit execution on first use of the +distribution. + +The install hook and metadata extension systems allow support for such +activities to be pursued independently by the individual platform +communities, while still interoperating with the cross-platform Python +tools. + +Legacy packages that expect to able to run code on target systems using +``setup.py install`` will no longer work correctly. Such packages will +already break when pip 1.4+ is configured to use a wheel cache directory. Changes to environment markers @@ -1805,8 +2101,9 @@ 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. +entirely. The combination of explicit support for post install hooks and the +metadata extension mechanism will hopefully prove to be a more useful +replacement. Updated obsolescence mechanism @@ -1824,22 +2121,55 @@ is not widely supported, and so removing it does not present any significant barrier to tools and projects adopting the new metadata 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 + +Included text documents +----------------------- + +Currently, PyPI attempts to determine the description's markup format by +rendering it as reStructuredText, and if that fails, treating it as plain +text. + +Furthermore, many projects simply read their long description in from an +existing README file in ``setup.py``. The popularity of this practice is +only expected to increase, as many online version control systems +(including both GitHub and BitBucket) automatically display such files +on the landing page for the project. + +Standardising on the inclusion of the long description as a separate +file in the ``dist-info`` directory allows this to be simplified: + +* An existing file can just be copied into the ``dist-info`` directory as + part of creating the sdist +* The expected markup format can be determined by inspecting the file + extension of the specified path + +Allowing the intended format to be stated explicitly in the path allows +the format guessing to be removed and more informative error reports to be +provided to users when a rendering error occurs. + +This is especially helpful 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 -================= +The document naming system used to achieve this then makes it relatively +straightforward to allow declaration of alternative markup formats like +HTML, Markdown and AsciiDoc through the use of appropriate file +extensions, as well as to define similar included documents for the +project's license and changelog. + +Grouping the included document names into a single top level field gives +automated tools the option of treating them as arbitrary documents without +worrying about their contents. + +Requiring that the included documents be added to the ``dist-info`` metadata +directory means that the complete metadata for the distribution can be +extracted from an sdist or binary archive simply by extracting that +directory, without needing to check for references to other files in the +sdist. + + +Appendix D: Deferred features +============================= Several potentially useful features have been deliberately deferred in order to better prioritise our efforts in migrating to the new metadata @@ -1847,15 +2177,26 @@ 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. +Once the ``pypi``, ``setuptools``, ``pip``, ``wheel`` and ``distlib`` +projects support creation and consumption of metadata 2.0, then we may +revisit the creation of metadata 2.1 with some or all of these additional +features. + + +MIME type registration +---------------------- + +At some point after acceptance of the PEP, I will likely submit the +following MIME type registration requests to IANA: + +* Full metadata: ``application/vnd.python.pymeta+json`` +* Abbreviated metadata: ``application/vnd.python.pymeta-short+json`` +* Essential dependency resolution metadata: + ``application/vnd.python.pymeta-dependencies+json`` + +It's even possible we may be able to just register the ``vnd.python`` +namespace under the banner of the PSF rather than having to register +the individual subformats. String methods in environment markers @@ -1870,61 +2211,82 @@ 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" - ] +Module and file listings +------------------------ + +Derived metadata giving the modules and files included in built +distributions may be useful at some point in the future. (At least RPM +provides this, and I believe the APT equivalent does as well) 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 --------------------------- - -The following draft metabuild operations have been deferred for now: +However, this is just extra info that doesn't impact reliably installing +from wheels, so it is a good candidate for postponing to metadata 2.1 +(at the earliest). + + +Additional install hooks +------------------------ + +In addition to the postinstall and preuninstall hooks described in the PEP, +other distribution systems (like RPM) include the notion of preinstall +and postuninstall hooks. These hooks would run with the runtime dependencies +installed, but without the distribution itself. These have been deliberately +omitted, as they're well suited to being explored further as metadata +extensions. + +Similarly, the idea of "optional" postinstall and preuninstall hooks can +be pursued as a metadata extension. + +By contrast, the mandatory postinstall and preuninstall hooks have been +included directly in the PEP, specifically to ensure installation tools +don't silently ignore them. This ensures users will either be able to +install such distributions, or else receive an explicit error at installation +time. + + +Metabuild system +---------------- + +This version of the metadata specification continues to use ``setup.py`` +and the distutils command syntax to invoke build and test related +operations on a source archive or VCS checkout. + +It may be desirable to replace these in the future with tool independent +entry points that support: * Generating the metadata file on a development system -* Generating a source archive on a development system +* Generating an sdist on a development system * Generating a binary archive on a build system +* Running the test suite on a built (but not installed) distribution 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 three operations will continue to be handled -through the ``distutils``/``setuptools`` command system: +sdist, source archive, and VCS checkout based installation to use the +existing ``setup.py`` based ``distutils`` command interface. + +In the meantime, the above operations will be handled through the +``distutils``/``setuptools`` command system: * ``python setup.py dist_info`` * ``python setup.py sdist`` +* ``python setup.py build_ext --inplace`` +* ``python setup.py test`` * ``python setup.py bdist_wheel`` -The following additional metabuild hooks may be added in metadata 2.1 to +The following metabuild hooks may be defined 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:: +* ``make_dist_info``: generate the sdist's dist_info directory +* ``make_sdist``: create the contents of an sdist +* ``build_dist``: create the contents of a binary wheel archive from an + unpacked sdist +* ``test_built_dist``: run the test suite for a built distribution + +Tentative signatures have been designed for those hooks, but in order to +better focus initial development efforts on the integration and installation +use cases, they will not be pursued further until metadata 2.1:: def make_dist_info(source_dir, info_dir): """Generate the contents of dist_info for an sdist archive @@ -1949,11 +2311,11 @@ 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 + def build_dist(sdist_dir, built_dir, info_dir, compatibility=None): + """Generate the contents of a binary wheel archive + + *sdist_dir* points to an unpacked sdist + *built_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 @@ -1965,36 +2327,93 @@ Returns the actual compatibility tag for the build """ -As with the existing metabuild hooks, checking for extras would be done + def test_built_dist(sdist_dir, built_dir, info_dir): + """Check a built (but not installed) distribution works as expected + + *sdist_dir* points to an unpacked sdist + *built_dir* points to a platform appropriate unpacked wheel archive + (which may be missing the wheel metadata directory) + *info_dir* points to the appropriate wheel metadata directory + + Requires that the distribution's test dependencies be installed + (indicated by the ``:test:`` extra). + + Returns ``True`` if the check passes, ``False`` otherwise. + """ + +As with the existing install 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 -================= +There are still a number of open questions with this design, such as whether +a single build hook is sufficient to cover both "build for testing" and +"prep for deployment", as well as various complexities like support for +cross-compilation of binaries, specification of target platforms and +Python versions when creating wheel files, etc. + +Opting to retain the status quo for now allows us to make progress on +improved metadata publication and binary installation support, rather than +having to delay that awaiting the creation of a viable metabuild framework. + + +Appendix E: 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). + +Disallowing underscores in distribution names +--------------------------------------------- + +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). + + +Allowing the use of Unicode in distribution names +------------------------------------------------- + +This PEP deliberately avoids following Python 3 down the path of arbitrary +Unicode identifiers, as 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). + +In addition, the existing tools really only work properly if you restrict +names to ASCII and changing that would require a *lot* of work for all +the automated tools in the chain. + +It may be reasonable to revisit this question at some point in the (distant) +future, but setting up a more reliable software distribution system is +challenging enough without adding more general Unicode identifier support +into the mix. + + +Single list for conditional and unconditional dependencies +---------------------------------------------------------- + +It's technically possible to store the conditional and unconditional +dependencies of each kind in a single list and switch the handling based on +the entry type (string or mapping). + +However, the current ``*requires`` vs ``*may-require`` two list design seems +easier to understand and work with, since it's only the conditional +dependencies that need to be checked against the requested extras list and +the target installation environment. + + +Depending on source labels +-------------------------- + +There is no mechanism to express a dependency on a source label - they +are included in the metadata for internal project reference only. Instead, +dependencies must be expressed in terms of either public versions or else +direct URL references. Alternative dependencies @@ -2019,7 +2438,7 @@ 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). +``supports_environments`` 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 @@ -2047,9 +2466,67 @@ 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 +However, it isn't clear there's any use case for doing 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). +the idea won't be reconsidered until metadata 2.1 at the earliest). + + +A hook to run tests against installed distributions +--------------------------------------------------- + +Earlier drafts of this PEP defined a hook for running automated +tests against an *installed* distribution. This isn't actually what you +generally want - you want the ability to test a *built* distribution, +potentially relying on files which won't be included in the binary archives. + +RPM's "check" step also runs between the build step and the install step, +rather than after the install step. + +Accordingly, the ``test_installed_dist`` hook has been removed, and the +``test_built_dist`` metabuild hook has been tentatively defined. However, +along with the rest of the metabuild hooks, further consideration has been +deferred until metadata 2.1 at the earliest. + + +Extensible signatures for the install hooks +------------------------------------------- + +The install hooks have been deliberately designed to NOT accept arbitary +keyword arguments that the hook implementation is then expected to ignore. + +The argument in favour of that API design technique is to allow the addition +of new optional arguments in the future, without requiring the definition +of a new install hook, or migration to version 3.0 of the metadata +specification. It is a technique very commonly seen in function wrappers +which merely pass arguments along to the inner function rather than +processing them directly. + +However, the install hooks are already designed to have access to the full +metadata for the distribution (including all metadata extensions and +the previous/next version when appropriate), as well as to the full target +deployment environment. + +This means there are two candidates for additional information that +could be passed as arbitrary keyword arguments: + +* installer dependent settings +* user provided installation options + +The first of those runs explicitly counter to one of the core goals of the +metadata 2.0 specification: decoupling the software developer's choice of +development and publication tools from the software integrator's choice of +integration and deployment tools. + +The second is a complex problem that has a readily available workaround in +the form of operating system level environment variables (this is also +one way to interoperate with platform specific installation tools). + +Alternatively, installer developers may either implicitly inject an +additional metadata extension when invoking the install hook, or else +define an alternate hook signature as a distinct metadata extension to be +provided by the distribution. Either of these approaches makes the +reliance on installer-dependent behaviour suitably explicit in either +the install hook implementation or the distribution metadata. References diff --git a/pep-0426/pymeta-schema.json b/pep-0426/pymeta-schema.json new file mode 100644 --- /dev/null +++ b/pep-0426/pymeta-schema.json @@ -0,0 +1,249 @@ +{ + "id": "http://www.python.org/dev/peps/pep-0426/", + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Metadata for Python Software Packages 2.0", + "type": "object", + "properties": { + "metadata_version": { + "description": "Version of the file format", + "type": "string", + "pattern": "^(\\d+(\\.\\d+)*)$" + }, + "generator": { + "description": "Name and version of the program that produced this file.", + "type": "string", + "pattern": "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])( \\((\\d+(\\.\\d+)*)((a|b|c|rc)(\\d+))?(\\.(post)(\\d+))?(\\.(dev)(\\d+))\\))?$" + }, + "name": { + "description": "The name of the distribution.", + "type": "string", + "pattern": "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])?$" + }, + "version": { + "description": "The distribution's public version identifier", + "type": "string", + "pattern": "^(\\d+(\\.\\d+)*)((a|b|c|rc)(\\d+))?(\\.(post)(\\d+))?(\\.(dev)(\\d+))?$" + }, + "source_label": { + "description": "A constrained identifying text string", + "type": "string", + "pattern": "^[0-9a-z_.-+]+$" + }, + "source_url": { + "description": "A string containing a full URL where the source for this specific version of the distribution can be downloaded.", + "type": "string", + "format": "uri" + }, + "summary": { + "description": "A one-line summary of what the distribution does.", + "type": "string" + }, + "document_names": { + "description": "Names of supporting metadata documents", + "type": "object", + "properties": { + "description": { + "type": "string", + "$ref": "#/definitions/document_name" + }, + "changelog": { + "type": "string", + "$ref": "#/definitions/document_name" + }, + "license": { + "type": "string", + "$ref": "#/definitions/document_name" + } + }, + "additionalProperties": false + }, + "keywords": { + "description": "A list of additional keywords to be used to assist searching for the distribution in a larger catalog.", + "type": "array", + "items": { + "type": "string" + } + }, + "license": { + "description": "A string indicating the license covering the distribution.", + "type": "string" + }, + "classifiers": { + "description": "A list of strings, with each giving a single classification value for the distribution.", + "type": "array", + "items": { + "type": "string" + } + }, + "contacts": { + "description": "A list of contributor entries giving the recommended contact points for getting more information about the project.", + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/contact" + } + }, + "contributors": { + "description": "A list of contributor entries for other contributors not already listed as current project points of contact.", + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/contact" + } + }, + "project_urls": { + "description": "A mapping of arbitrary text labels to additional URLs relevant to the project.", + "type": "object" + }, + "extras": { + "description": "A list of optional sets of dependencies that may be used to define conditional dependencies in \"may_require\" and similar fields.", + "type": "array", + "items": { + "type": "string", + "$ref": "#/definitions/extra_name" + } + }, + "distributes": { + "description": "A list of subdistributions made available through this metadistribution.", + "type": "array", + "$ref": "#/definitions/dependencies" + }, + "may_distribute": { + "description": "A list of subdistributions that may be made available through this metadistribution, based on the extras requested and the target deployment environment.", + "$ref": "#/definitions/conditional_dependencies" + }, + "run_requires": { + "description": "A list of other distributions needed when to run this distribution.", + "type": "array", + "$ref": "#/definitions/dependencies" + }, + "run_may_require": { + "description": "A list of other distributions that may be needed when this distribution is deployed, based on the extras requested and the target deployment environment.", + "$ref": "#/definitions/conditional_dependencies" + }, + "test_requires": { + "description": "A list of other distributions needed when this distribution is tested.", + "type": "array", + "$ref": "#/definitions/dependencies" + }, + "test_may_require": { + "description": "A list of other distributions that may be needed when this distribution is tested, based on the extras requested and the target deployment environment.", + "type": "array", + "$ref": "#/definitions/conditional_dependencies" + }, + "build_requires": { + "description": "A list of other distributions needed when this distribution is built.", + "type": "array", + "$ref": "#/definitions/dependencies" + }, + "build_may_require": { + "description": "A list of other distributions that may be needed when this distribution is built, based on the extras requested and the target deployment environment.", + "type": "array", + "$ref": "#/definitions/conditional_dependencies" + }, + "dev_requires": { + "description": "A list of other distributions needed when this distribution is developed.", + "type": "array", + "$ref": "#/definitions/dependencies" + }, + "dev_may_require": { + "description": "A list of other distributions that may be needed when this distribution is developed, based on the extras requested and the target deployment environment.", + "type": "array", + "$ref": "#/definitions/conditional_dependencies" + }, + "provides": { + "description": "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.", + "type": "array", + "items": { + "type": "string" + } + }, + "obsoleted_by": { + "description": "A string that indicates that this project is no longer being developed. The named project provides a substitute or replacement.", + "type": "string", + "$ref": "#/definitions/version_specifier" + }, + "supports_environments": { + "description": "A list of strings specifying the environments that the distribution explicitly supports.", + "type": "array", + "items": { + "type": "string", + "$ref": "#/definitions/environment_marker" + } + }, + "metabuild_hooks": { + "description": "The metabuild_hooks field is used to define various operations that may be invoked on a distribution in a platform independent manner.", + "type": "object" + }, + "extensions": { + "description": "Extensions to the metadata may be present in a mapping under the 'extensions' key.", + "type": "object" + } + }, + + "required": ["metadata_version", "name", "version"], + "additionalProperties": false, + + "definitions": { + "contact": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "url": { + "type": "string" + }, + "role": { + "type": "string" + } + }, + "required": ["name"], + "additionalProperties": false + }, + "dependencies": { + "type": "array", + "items": { + "type": "string", + "$ref": "#/definitions/version_specifier" + } + }, + "conditional_dependencies": { + "type": "array", + "items": { + "type": "object", + "properties": { + "extra": { + "type": "string", + "$ref": "#/definitions/extra_name" + }, + "environment": { + "type": "string", + "$ref": "#/definitions/environment_marker" + }, + "dependencies": { + "type": "array", + "$ref": "#/definitions/dependencies" + } + }, + "required": ["dependencies"], + "additionalProperties": false + } + }, + "version_specifier": { + "type": "string" + }, + "extra_name": { + "type": "string" + }, + "environment_marker": { + "type": "string" + }, + "document_name": { + "type": "string" + } + } +} diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -5,7 +5,7 @@ Author: Barry Warsaw , Eli Bendersky , Ethan Furman -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 2013-02-23 @@ -467,6 +467,10 @@ ... cat = 3 ... dog = 4 +The reason for defaulting to ``1`` as the starting number and not ``0`` is +that ``0`` is ``False`` in a boolean sense, but enum members all evaluate +to ``True``. + Proposed variations =================== diff --git a/pep-0440.txt b/pep-0440.txt --- a/pep-0440.txt +++ b/pep-0440.txt @@ -9,7 +9,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 18 Mar 2013 -Post-History: 30 Mar 2013, 27-May-2013 +Post-History: 30 Mar 2013, 27 May 2013, 20 Jun 2013 Replaces: 386 @@ -27,7 +27,7 @@ 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. + part of the final specification (except for this one). Definitions @@ -40,7 +40,7 @@ The following terms are to be interpreted as described in PEP 426: * "Distributions" -* "Versions" +* "Releases" * "Build tools" * "Index servers" * "Publication tools" @@ -52,9 +52,13 @@ 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. +Distributions are identified by a public version identifier which +supports all defined version comparison operations + +Distributions may also define a source label, which is not used by +automated tools. Source labels are useful when a project internal +versioning scheme requires translation to create a compliant public +version identifier. The version scheme is used both to describe the distribution version provided by a particular distribution archive, as well as to place @@ -84,7 +88,7 @@ * Post-release segment: ``.postN`` * Development release segment: ``.devN`` -Any given version will be a "release", "pre-release", "post-release" or +Any given release will be a "final release", "pre-release", "post-release" or "developmental release" as defined in the following sections. .. note:: @@ -105,28 +109,37 @@ Source labels are text strings with minimal defined semantics. 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. +and URLs, and to avoid formatting inconsistences in hexadecimal hash +representations they MUST be limited to the following set of permitted +characters: -In addition, source labels MUST be unique within a given distribution. +* Lowercase ASCII letters (``[a-z]``) +* ASCII digits (``[0-9]``) +* underscores (``_``) +* hyphens (``-``) +* periods (``.``) +* plus signs (``+``) -As with distribution names, all comparisons of source labels MUST be case -insensitive. +Source labels MUST start and end with an ASCII letter or digit. +Source labels MUST be unique within each project and MUST NOT match any +defined version for the project. -Releases --------- -A version identifier that consists solely of a release segment is termed -a "release". +Final releases +-------------- -The release segment consists of one or more non-negative integer values, -separated by dots:: +A version identifier that consists solely of a release segment is +termed a "final release". + +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. +Final releases within a project MUST be numbered in a consistently +increasing fashion, otherwise automated tools will not be able to upgrade +them correctly. Comparison and ordering of release segments considers the numeric value of each component of the release segment in turn. When comparing release @@ -157,8 +170,8 @@ 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 +A release series is any set of final 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:: @@ -206,8 +219,8 @@ 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 +Some projects use post-releases to address minor errors in a final 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 @@ -371,7 +384,7 @@ .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 +component) although they are semantically equivalent. Tools MAY reject this case as ambiguous and remain in compliance with the PEP. Within an alpha (``1.0a1``), beta (``1.0b1``), or release candidate @@ -506,6 +519,22 @@ version comparison semantics. +Olson database versioning +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``pytz`` project inherits its versioning scheme from the corresponding +Olson timezone database versioning scheme: the year followed by a lowercase +character indicating the version of the database within that year. + +This can be translated to a compliant 3-part version identifier as +``0..``, where the serial starts at zero (for the 'a' +release) and is incremented with each subsequent database update within the +year. + +As with other translated version identifiers, the corresponding Olson +database version would be recorded in the source label field. + + Version specifiers ================== @@ -521,7 +550,6 @@ * ``~=``: `Compatible release`_ clause * ``==``: `Version matching`_ clause * ``!=``: `Version exclusion`_ clause -* ``is``: `Source reference`_ clause * ``<=``, ``>=``: `Inclusive ordered comparison`_ clause * ``<``, ``>``: `Exclusive ordered comparison`_ clause @@ -605,6 +633,11 @@ release segment to ensure the release segments are compared with the same length. +Whether or not strict version matching is appropriate depends on the specific +use case for the version specifier. Automated tools SHOULD at least issue +warnings and MAY reject them entirely when strict version matches are used +inappropriately. + 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 @@ -645,75 +678,6 @@ != 1.1.* # Same prefix, so 1.1.post1 does not match clause -Source reference ----------------- - -A source reference includes the source reference operator ``is`` and -a source label or a source URL. - -Installation tools MAY also permit direct references to a platform -appropriate binary archive in a source reference clause. - -Publication tools and public index servers SHOULD NOT permit direct -references to a platform appropriate binary archive in a source -reference clause. - -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 source reference could be used to depend directly on a -version control hash based identifier rather than the translated public -version:: - - exact-dependency (is 1.3.7+build.11.e0f985a) - -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 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 source archive may be referenced directly:: - - pip (is file:///localbuilds/pip-1.3.1.zip) - -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 -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. - -The use of ``is`` when defining dependencies for published distributions -is strongly discouraged as it greatly complicates the deployment of -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. - - Inclusive ordered comparison ---------------------------- @@ -752,62 +716,108 @@ ------------------------ 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 +excluded from all version specifiers, *unless* they are already present +on the system, explicitly requested by the user, or if the only available +version that satisfies the version specifier is a pre-release. By default, dependency resolution tools SHOULD: * accept already installed 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 +* accept remotely available pre-releases for version specifiers where + there is no final or post release that satisfies the version specifier * exclude all other pre-releases from consideration +Dependency resolution tools MAY issue a warning if a pre-release is needed +to satisfy a version specifier. + 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) + warning if a pre-release is already installed locally, or if a + pre-release is the only way to satisfy a particular specifier) 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 in -version specifiers - they are always included unless explicitly excluded. +Post-releases and final 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``: version 3.1 or later, but not version 4.0 or later. +* ``3.1.2``: version 3.1.2 or later, but not version 3.2.0 or later. +* ``3.1a1``: version 3.1a1 or later, but not version 4.0 or later. * ``== 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.*``: any version that starts with 3.1. 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. + not version 3.2.0 or later. + + +Direct references +================= + +Some automated tools may permit the use of a direct reference as an +alternative to a normal version specifier. A direct reference consists of +the word ``from`` and an explicit URL. + +Whether or not direct references are appropriate depends on the specific +use case for the version specifier. Automated tools SHOULD at least issue +warnings and MAY reject them entirely when direct references are used +inappropriately. + +Public index servers SHOULD NOT allow the use of direct references in +uploaded distributions. Direct references are intended as a tool for +software integrators rather than publishers. + +Depending on the use case, some appropriate targets for a direct URL +reference may be a valid ``source_url`` entry (see PEP 426), an sdist, or +a wheel binary archive. The exact URLs and targets supported will be tool +dependent. + +For example, a local source archive may be referenced directly:: + + pip (from file:///localbuilds/pip-1.3.1.zip) + +Alternatively, a prebuilt archive may also be referenced:: + + pip (from file:///localbuilds/pip-1.3.1-py33-none-any.whl) + +All direct references that do not refer to a local file URL SHOULD +specify a secure transport mechanism (such as ``https``), include an +expected hash value in the URL for verification purposes, or both. If an +insecure transport is specified without any hash information, with hash +information that the tool doesn't understand, or with a selected hash +algorithm that the tool considers too weak to trust, 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 and wheel references, an expected hash value may be +specified by including a ``=`` entry as +part of the URL fragment. + +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. + +Remote URL examples:: + + pip (from https://github.com/pypa/pip/archive/1.3.1.zip) + pip (from http://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686) + pip (from git+https://github.com/pypa/pip.git at 1.3.1) Updating the versioning specification @@ -825,28 +835,30 @@ * Moved the description of version specifiers into the versioning PEP -* added the "source 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 "source reference" clause +* Added the "direct reference" concept as a standard notation for direct + references to resources (rather than each tool needing to invents its own) -* added the trailing wildcard syntax for prefix based version matching +* Added the "compatible release" clause + +* Added the trailing wildcard syntax for prefix based version matching and exclusion -* changed the top level sort position of the ``.devN`` suffix +* Changed the top level sort position of the ``.devN`` suffix -* allowed single value version numbers +* Allowed single value version numbers -* explicit exclusion of leading or trailing whitespace +* Explicit exclusion of leading or trailing whitespace -* explicit criterion for the exclusion of date based versions +* Explicit criterion for the exclusion of date based versions -* implicitly exclude pre-releases unless explicitly requested +* Implicitly exclude pre-releases unless they're already present or + needed to satisfy a dependency -* treat post releases the same way as unqualified releases +* Treat post releases the same way as unqualified releases * Discuss ordering and dependencies across metadata versions @@ -995,11 +1007,12 @@ 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. +accept a pre-release version as satisfying a dependency, while still +allowing pre-release versions to be retrieved automatically when that's the +only way to satisfy a dependency. The "some forward compatibility assumed" default version constraint is -taken directly from the Ruby community's "pessimistic version constraint" +derived 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 @@ -1022,16 +1035,26 @@ 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. +and the desired pre- and post-release handling semantics for ``<`` and ``>`` +ordered comparison clauses. -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``. + +Adding direct references +------------------------ + +Direct references are added as an "escape clause" to handle messy real +world situations that don't map neatly to the standard distribution model. +This includes dependencies on unpublished software for internal use, as well +as handling the more complex compatibility issues that may arise when +wrapping third party libraries as C extensions (this is of especial concern +to the scientific community). + +Index servers are deliberately given a lot of freedom to disallow direct +references, since they're intended primarily as a tool for integrators +rather than publishers. PyPI in particular is currently going through the +process of *eliminating* dependencies on external references, as unreliable +external services have the effect of slowing down installation operations, +as well as reducing PyPI's own apparent reliability. References diff --git a/pep-0442.txt b/pep-0442.txt --- a/pep-0442.txt +++ b/pep-0442.txt @@ -4,13 +4,13 @@ Last-Modified: $Date$ Author: Antoine Pitrou BDFL-Delegate: Benjamin Peterson -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 2013-05-18 Python-Version: 3.4 Post-History: 2013-05-18 -Resolution: TBD +Resolution: http://mail.python.org/pipermail/python-dev/2013-June/126746.html Abstract @@ -201,8 +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 when the object becomes unreachable again. +once, even if it was resurrected afterwards. For CI objects, the order in which finalizers are called (step 2 above) is undefined. diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: ?ukasz Langa Discussions-To: Python-Dev -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 22-May-2013 @@ -193,48 +193,37 @@ importantly, it introduces support for Abstract Base Classes (ABC). 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:: +dispatch algorithm switches to an extended form of C3 linearization, +which includes the relevant ABCs in the MRO of the provided argument. +The algorithm inserts ABCs where their functionality is introduced, i.e. +``issubclass(cls, abc)`` returns ``True`` for the class itself but +returns ``False`` for all its direct base classes. Implicit ABCs for +a given class (either registered or inferred from the presence of +a special method like ``__len__()``) are inserted directly after the +last ABC explicitly listed in the MRO of said class. - 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 - -In its most basic form, it returns the MRO for the given type:: +In its most basic form, this linearization 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:: +When the second argument contains 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, all dispatch decisions are cached. The cache is invalidated on registering new 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:: +``register()`` on an ABC to implicitly subclass it. In the latter case, +it is possible to create a situation with ambiguous dispatch, for +instance:: >>> from collections import Iterable, Container >>> class P: @@ -261,20 +250,38 @@ 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:: +Note that this exception would not be raised if one or more ABCs had +been provided explicitly 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) + ... return value in range(10) ... >>> g(Ten()) 'iterable' +A similar conflict arises when subclassing an ABC is inferred from the +presence of a special method like ``__len__()`` or ``__contains__()``:: + + >>> class Q: + ... def __contains__(self, value): + ... return False + ... + >>> issubclass(Q, Container) + True + >>> Iterable.register(Q) + >>> g(Q()) + Traceback (most recent call last): + ... + RuntimeError: Ambiguous dispatch: + or + +An early version of the PEP contained a custom approach that was simpler +but created a number of edge cases with surprising results [#why-c3]_. Usage Patterns ============== @@ -378,6 +385,8 @@ a particular annotation style". (http://www.python.org/dev/peps/pep-0008) +.. [#why-c3] http://bugs.python.org/issue18244 + .. [#pep-3124] http://www.python.org/dev/peps/pep-3124/ .. [#peak-rules] http://peak.telecommunity.com/DevCenter/PEAK_2dRules diff --git a/pep-0445.txt b/pep-0445.txt new file mode 100644 --- /dev/null +++ b/pep-0445.txt @@ -0,0 +1,773 @@ +PEP: 445 +Title: Add new APIs to customize Python memory allocators +Version: $Revision$ +Last-Modified: $Date$ +Author: Victor Stinner +BDFL-Delegate: Antoine Pitrou +Status: Accepted +Type: Standards Track +Content-Type: text/x-rst +Created: 15-june-2013 +Python-Version: 3.4 +Resolution: http://mail.python.org/pipermail/python-dev/2013-July/127222.html + +Abstract +======== + +This PEP proposes new Application Programming Interfaces (API) to customize +Python memory allocators. The only implementation required to conform to +this PEP is CPython, but other implementations may choose to be compatible, +or to re-use a similar scheme. + + +Rationale +========= + +Use cases: + +* Applications embedding Python which want to isolate Python memory from + the memory of the application, or want to use a different memory + allocator optimized for its Python usage +* Python running on embedded devices with low memory and slow CPU. + A custom memory allocator can be used for efficiency and/or to get + access all the memory of the device. +* Debug tools for memory allocators: + + - track the memory usage (find memory leaks) + - get the location of a memory allocation: Python filename and line + number, and the size of a memory block + - detect buffer underflow, buffer overflow and misuse of Python + allocator APIs (see `Redesign Debug Checks on Memory Block + Allocators as Hooks`_) + - force memory allocations to fail to test handling of the + ``MemoryError`` exception + + +Proposal +======== + +New Functions and Structures +---------------------------- + +* Add a new GIL-free (no need to hold the GIL) memory allocator: + + - ``void* PyMem_RawMalloc(size_t size)`` + - ``void* PyMem_RawRealloc(void *ptr, size_t new_size)`` + - ``void PyMem_RawFree(void *ptr)`` + - The newly allocated memory will not have been initialized in any + way. + - Requesting zero bytes returns a distinct non-*NULL* pointer if + possible, as if ``PyMem_Malloc(1)`` had been called instead. + +* Add a new ``PyMemAllocator`` structure:: + + typedef struct { + /* user context passed as the first argument to the 3 functions */ + void *ctx; + + /* allocate a memory block */ + void* (*malloc) (void *ctx, size_t size); + + /* allocate or resize a memory block */ + void* (*realloc) (void *ctx, void *ptr, size_t new_size); + + /* release a memory block */ + void (*free) (void *ctx, void *ptr); + } PyMemAllocator; + +* Add a new ``PyMemAllocatorDomain`` enum to choose the Python + allocator domain. Domains: + + - ``PYMEM_DOMAIN_RAW``: ``PyMem_RawMalloc()``, ``PyMem_RawRealloc()`` + and ``PyMem_RawFree()`` + + - ``PYMEM_DOMAIN_MEM``: ``PyMem_Malloc()``, ``PyMem_Realloc()`` and + ``PyMem_Free()`` + + - ``PYMEM_DOMAIN_OBJ``: ``PyObject_Malloc()``, ``PyObject_Realloc()`` + and ``PyObject_Free()`` + +* Add new functions to get and set memory block allocators: + + - ``void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)`` + - ``void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)`` + - The new allocator must return a distinct non-*NULL* pointer when + requesting zero bytes + - For the ``PYMEM_DOMAIN_RAW`` domain, the allocator must be + thread-safe: the GIL is not held when the allocator is called. + +* Add a new ``PyObjectArenaAllocator`` structure:: + + typedef struct { + /* user context passed as the first argument to the 2 functions */ + void *ctx; + + /* allocate an arena */ + void* (*alloc) (void *ctx, size_t size); + + /* release an arena */ + void (*free) (void *ctx, void *ptr, size_t size); + } PyObjectArenaAllocator; + +* Add new functions to get and set the arena allocator used by + *pymalloc*: + + - ``void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)`` + - ``void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)`` + +* Add a new function to reinstall the debug checks on memory allocators when + a memory allocator is replaced with ``PyMem_SetAllocator()``: + + - ``void PyMem_SetupDebugHooks(void)`` + - Install the debug hooks on all memory block allocators. The function can be + called more than once, hooks are only installed once. + - The function does nothing is Python is not compiled in debug mode. + +* Memory block allocators always return *NULL* if *size* is greater than + ``PY_SSIZE_T_MAX``. The check is done before calling the inner + function. + +.. note:: + The *pymalloc* allocator is optimized for objects smaller than 512 bytes + with a short lifetime. It uses memory mappings with a fixed size of 256 + KB called "arenas". + +Here is how the allocators are set up by default: + +* ``PYMEM_DOMAIN_RAW``, ``PYMEM_DOMAIN_MEM``: ``malloc()``, + ``realloc()`` and ``free()``; call ``malloc(1)`` when requesting zero + bytes +* ``PYMEM_DOMAIN_OBJ``: *pymalloc* allocator which falls back on + ``PyMem_Malloc()`` for allocations larger than 512 bytes +* *pymalloc* arena allocator: ``VirtualAlloc()`` and ``VirtualFree()`` on + Windows, ``mmap()`` and ``munmap()`` when available, or ``malloc()`` + and ``free()`` + + +Redesign Debug Checks on Memory Block Allocators as Hooks +--------------------------------------------------------- + +Since Python 2.3, Python implements different checks on memory +allocators in debug mode: + +* Newly allocated memory is filled with the byte ``0xCB``, freed memory + is filled with the byte ``0xDB``. +* Detect API violations, ex: ``PyObject_Free()`` called on a memory + block allocated by ``PyMem_Malloc()`` +* Detect write before the start of the buffer (buffer underflow) +* Detect write after the end of the buffer (buffer overflow) + +In Python 3.3, the checks are installed by replacing ``PyMem_Malloc()``, +``PyMem_Realloc()``, ``PyMem_Free()``, ``PyObject_Malloc()``, +``PyObject_Realloc()`` and ``PyObject_Free()`` using macros. The new +allocator allocates a larger buffer and writes a pattern to detect buffer +underflow, buffer overflow and use after free (by filling the buffer with +the byte ``0xDB``). It uses the original ``PyObject_Malloc()`` +function to allocate memory. So ``PyMem_Malloc()`` and +``PyMem_Realloc()`` indirectly call``PyObject_Malloc()`` and +``PyObject_Realloc()``. + +This PEP redesigns the debug checks as hooks on the existing allocators +in debug mode. Examples of call traces without the hooks: + +* ``PyMem_RawMalloc()`` => ``_PyMem_RawMalloc()`` => ``malloc()`` +* ``PyMem_Realloc()`` => ``_PyMem_RawRealloc()`` => ``realloc()`` +* ``PyObject_Free()`` => ``_PyObject_Free()`` + +Call traces when the hooks are installed (debug mode): + +* ``PyMem_RawMalloc()`` => ``_PyMem_DebugMalloc()`` + => ``_PyMem_RawMalloc()`` => ``malloc()`` +* ``PyMem_Realloc()`` => ``_PyMem_DebugRealloc()`` + => ``_PyMem_RawRealloc()`` => ``realloc()`` +* ``PyObject_Free()`` => ``_PyMem_DebugFree()`` + => ``_PyObject_Free()`` + +As a result, ``PyMem_Malloc()`` and ``PyMem_Realloc()`` now call +``malloc()`` and ``realloc()`` in both release mode and debug mode, +instead of calling ``PyObject_Malloc()`` and ``PyObject_Realloc()`` in +debug mode. + +When at least one memory allocator is replaced with +``PyMem_SetAllocator()``, the ``PyMem_SetupDebugHooks()`` function must +be called to reinstall the debug hooks on top on the new allocator. + + +Don't call malloc() directly anymore +------------------------------------ + +``PyObject_Malloc()`` falls back on ``PyMem_Malloc()`` instead of +``malloc()`` if size is greater or equal than 512 bytes, and +``PyObject_Realloc()`` falls back on ``PyMem_Realloc()`` instead of +``realloc()`` + +Direct calls to ``malloc()`` are replaced with ``PyMem_Malloc()``, or +``PyMem_RawMalloc()`` if the GIL is not held. + +External libraries like zlib or OpenSSL can be configured to allocate memory +using ``PyMem_Malloc()`` or ``PyMem_RawMalloc()``. If the allocator of a +library can only be replaced globally (rather than on an object-by-object +basis), it shouldn't be replaced when Python is embedded in an application. + +For the "track memory usage" use case, it is important to track memory +allocated in external libraries to have accurate reports, because these +allocations can be large (e.g. they can raise a ``MemoryError`` exception) +and would otherwise be missed in memory usage reports. + + +Examples +======== + +Use case 1: Replace Memory Allocators, keep pymalloc +---------------------------------------------------- + +Dummy example wasting 2 bytes per memory block, +and 10 bytes per *pymalloc* arena:: + + #include + + size_t alloc_padding = 2; + size_t arena_padding = 10; + + void* my_malloc(void *ctx, size_t size) + { + int padding = *(int *)ctx; + return malloc(size + padding); + } + + void* my_realloc(void *ctx, void *ptr, size_t new_size) + { + int padding = *(int *)ctx; + return realloc(ptr, new_size + padding); + } + + void my_free(void *ctx, void *ptr) + { + free(ptr); + } + + void* my_alloc_arena(void *ctx, size_t size) + { + int padding = *(int *)ctx; + return malloc(size + padding); + } + + void my_free_arena(void *ctx, void *ptr, size_t size) + { + free(ptr); + } + + void setup_custom_allocator(void) + { + PyMemAllocator alloc; + PyObjectArenaAllocator arena; + + alloc.ctx = &alloc_padding; + alloc.malloc = my_malloc; + alloc.realloc = my_realloc; + alloc.free = my_free; + + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); + /* leave PYMEM_DOMAIN_OBJ unchanged, use pymalloc */ + + arena.ctx = &arena_padding; + arena.alloc = my_alloc_arena; + arena.free = my_free_arena; + PyObject_SetArenaAllocator(&arena); + + PyMem_SetupDebugHooks(); + } + + +Use case 2: Replace Memory Allocators, override pymalloc +-------------------------------------------------------- + +If you have a dedicated allocator optimized for allocations of objects +smaller than 512 bytes with a short lifetime, pymalloc can be overriden +(replace ``PyObject_Malloc()``). + +Dummy example wasting 2 bytes per memory block:: + + #include + + size_t padding = 2; + + void* my_malloc(void *ctx, size_t size) + { + int padding = *(int *)ctx; + return malloc(size + padding); + } + + void* my_realloc(void *ctx, void *ptr, size_t new_size) + { + int padding = *(int *)ctx; + return realloc(ptr, new_size + padding); + } + + void my_free(void *ctx, void *ptr) + { + free(ptr); + } + + void setup_custom_allocator(void) + { + PyMemAllocator alloc; + alloc.ctx = &padding; + alloc.malloc = my_malloc; + alloc.realloc = my_realloc; + alloc.free = my_free; + + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); + PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); + + PyMem_SetupDebugHooks(); + } + +The *pymalloc* arena does not need to be replaced, because it is no more +used by the new allocator. + + +Use case 3: Setup Hooks On Memory Block Allocators +-------------------------------------------------- + +Example to setup hooks on all memory block allocators:: + + struct { + PyMemAllocator raw; + PyMemAllocator mem; + PyMemAllocator obj; + /* ... */ + } hook; + + static void* hook_malloc(void *ctx, size_t size) + { + PyMemAllocator *alloc = (PyMemAllocator *)ctx; + void *ptr; + /* ... */ + ptr = alloc->malloc(alloc->ctx, size); + /* ... */ + return ptr; + } + + static void* hook_realloc(void *ctx, void *ptr, size_t new_size) + { + PyMemAllocator *alloc = (PyMemAllocator *)ctx; + void *ptr2; + /* ... */ + ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); + /* ... */ + return ptr2; + } + + static void hook_free(void *ctx, void *ptr) + { + PyMemAllocator *alloc = (PyMemAllocator *)ctx; + /* ... */ + alloc->free(alloc->ctx, ptr); + /* ... */ + } + + void setup_hooks(void) + { + PyMemAllocator alloc; + static int installed = 0; + + if (installed) + return; + installed = 1; + + alloc.malloc = hook_malloc; + alloc.realloc = hook_realloc; + alloc.free = hook_free; + PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &hook.raw); + PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &hook.mem); + PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &hook.obj); + + alloc.ctx = &hook.raw; + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); + + alloc.ctx = &hook.mem; + PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); + + alloc.ctx = &hook.obj; + PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); + } + +.. note:: + ``PyMem_SetupDebugHooks()`` does not need to be called because + memory allocator are not replaced: the debug checks on memory + block allocators are installed automatically at startup. + + +Performances +============ + +The implementation of this PEP (issue #3329) has no visible overhead on +the Python benchmark suite. + +Results of the `Python benchmarks suite +`_ (-b 2n3): some tests are 1.04x +faster, some tests are 1.04 slower. Results of pybench microbenchmark: +"+0.1%" slower globally (diff between -4.9% and +5.6%). + +The full output of benchmarks is attached to the issue #3329. + + +Rejected Alternatives +===================== + +More specific functions to get/set memory allocators +---------------------------------------------------- + +It was originally proposed a larger set of C API functions, with one pair +of functions for each allocator domain: + +* ``void PyMem_GetRawAllocator(PyMemAllocator *allocator)`` +* ``void PyMem_GetAllocator(PyMemAllocator *allocator)`` +* ``void PyObject_GetAllocator(PyMemAllocator *allocator)`` +* ``void PyMem_SetRawAllocator(PyMemAllocator *allocator)`` +* ``void PyMem_SetAllocator(PyMemAllocator *allocator)`` +* ``void PyObject_SetAllocator(PyMemAllocator *allocator)`` + +This alternative was rejected because it is not possible to write +generic code with more specific functions: code must be duplicated for +each memory allocator domain. + + +Make PyMem_Malloc() reuse PyMem_RawMalloc() by default +------------------------------------------------------ + +If ``PyMem_Malloc()`` called ``PyMem_RawMalloc()`` by default, +calling ``PyMem_SetAllocator(PYMEM_DOMAIN_RAW, alloc)`` would also +patch ``PyMem_Malloc()`` indirectly. + +This alternative was rejected because ``PyMem_SetAllocator()`` would +have a different behaviour depending on the domain. Always having the +same behaviour is less error-prone. + + +Add a new PYDEBUGMALLOC environment variable +-------------------------------------------- + +It was proposed to add a new ``PYDEBUGMALLOC`` environment variable to +enable debug checks on memory block allocators. It would have had the same +effect as calling the ``PyMem_SetupDebugHooks()``, without the need +to write any C code. Another advantage is to allow to enable debug checks +even in release mode: debug checks would always be compiled in, but only +enabled when the environment variable is present and non-empty. + +This alternative was rejected because a new environment variable would +make Python initialization even more complex. `PEP 432 +`_ tries to simplify the +CPython startup sequence. + + +Use macros to get customizable allocators +----------------------------------------- + +To have no overhead in the default configuration, customizable +allocators would be an optional feature enabled by a configuration +option or by macros. + +This alternative was rejected because the use of macros implies having +to recompile extensions modules to use the new allocator and allocator +hooks. Not having to recompile Python nor extension modules makes debug +hooks easier to use in practice. + + +Pass the C filename and line number +----------------------------------- + +Define allocator functions as macros using ``__FILE__`` and ``__LINE__`` +to get the C filename and line number of a memory allocation. + +Example of ``PyMem_Malloc`` macro with the modified +``PyMemAllocator`` structure:: + + typedef struct { + /* user context passed as the first argument + to the 3 functions */ + void *ctx; + + /* allocate a memory block */ + void* (*malloc) (void *ctx, const char *filename, int lineno, + size_t size); + + /* allocate or resize a memory block */ + void* (*realloc) (void *ctx, const char *filename, int lineno, + void *ptr, size_t new_size); + + /* release a memory block */ + void (*free) (void *ctx, const char *filename, int lineno, + void *ptr); + } PyMemAllocator; + + void* _PyMem_MallocTrace(const char *filename, int lineno, + size_t size); + + /* the function is still needed for the Python stable ABI */ + void* PyMem_Malloc(size_t size); + + #define PyMem_Malloc(size) \ + _PyMem_MallocTrace(__FILE__, __LINE__, size) + +The GC allocator functions would also have to be patched. For example, +``_PyObject_GC_Malloc()`` is used in many C functions and so objects of +different types would have the same allocation location. + +This alternative was rejected because passing a filename and a line +number to each allocator makes the API more complex: pass 3 new +arguments (ctx, filename, lineno) to each allocator function, instead of +just a context argument (ctx). Having to also modify GC allocator +functions adds too much complexity for a little gain. + + +GIL-free PyMem_Malloc() +----------------------- + +In Python 3.3, when Python is compiled in debug mode, ``PyMem_Malloc()`` +indirectly calls ``PyObject_Malloc()`` which requires the GIL to be +held (it isn't thread-safe). That's why ``PyMem_Malloc()`` must be called +with the GIL held. + +This PEP changes ``PyMem_Malloc()``: it now always calls ``malloc()`` +rather than ``PyObject_Malloc()``. The "GIL must be held" restriction +could therefore be removed from ``PyMem_Malloc()``. + +This alternative was rejected because allowing to call +``PyMem_Malloc()`` without holding the GIL can break applications +which setup their own allocators or allocator hooks. Holding the GIL is +convenient to develop a custom allocator: no need to care about other +threads. It is also convenient for a debug allocator hook: Python +objects can be safely inspected, and the C API may be used for reporting. + +Moreover, calling ``PyGILState_Ensure()`` in a memory allocator has +unexpected behaviour, especially at Python startup and when creating of a +new Python thread state. It is better to free custom allocators of +the responsibility of acquiring the GIL. + + +Don't add PyMem_RawMalloc() +--------------------------- + +Replace ``malloc()`` with ``PyMem_Malloc()``, but only if the GIL is +held. Otherwise, keep ``malloc()`` unchanged. + +The ``PyMem_Malloc()`` is used without the GIL held in some Python +functions. For example, the ``main()`` and ``Py_Main()`` functions of +Python call ``PyMem_Malloc()`` whereas the GIL do not exist yet. In this +case, ``PyMem_Malloc()`` would be replaced with ``malloc()`` (or +``PyMem_RawMalloc()``). + +This alternative was rejected because ``PyMem_RawMalloc()`` is required +for accurate reports of the memory usage. When a debug hook is used to +track the memory usage, the memory allocated by direct calls to +``malloc()`` cannot be tracked. ``PyMem_RawMalloc()`` can be hooked and +so all the memory allocated by Python can be tracked, including +memory allocated without holding the GIL. + + +Use existing debug tools to analyze memory use +---------------------------------------------- + +There are many existing debug tools to analyze memory use. Some +examples: `Valgrind `_, `Purify +`_, `Clang AddressSanitizer +`_, `failmalloc +`_, etc. + +The problem is to retrieve the Python object related to a memory pointer +to read its type and/or its content. Another issue is to retrieve the +source of the memory allocation: the C backtrace is usually useless +(same reasoning than macros using ``__FILE__`` and ``__LINE__``, see +`Pass the C filename and line number`_), the Python filename and line +number (or even the Python traceback) is more useful. + +This alternative was rejected because classic tools are unable to +introspect Python internals to collect such information. Being able to +setup a hook on allocators called with the GIL held allows to collect a +lot of useful data from Python internals. + + +Add a msize() function +---------------------- + +Add another function to ``PyMemAllocator`` and +``PyObjectArenaAllocator`` structures:: + + size_t msize(void *ptr); + +This function returns the size of a memory block or a memory mapping. +Return (size_t)-1 if the function is not implemented or if the pointer +is unknown (ex: NULL pointer). + +On Windows, this function can be implemented using ``_msize()`` and +``VirtualQuery()``. + +The function can be used to implement a hook tracking the memory usage. +The ``free()`` method of an allocator only gets the address of a memory +block, whereas the size of the memory block is required to update the +memory usage. + +The additional ``msize()`` function was rejected because only few +platforms implement it. For example, Linux with the GNU libc does not +provide a function to get the size of a memory block. ``msize()`` is not +currently used in the Python source code. The function would only be +used to track memory use, and make the API more complex. A debug hook +can implement the function internally, there is no need to add it to +``PyMemAllocator`` and ``PyObjectArenaAllocator`` structures. + + +No context argument +------------------- + +Simplify the signature of allocator functions, remove the context +argument: + +* ``void* malloc(size_t size)`` +* ``void* realloc(void *ptr, size_t new_size)`` +* ``void free(void *ptr)`` + +It is likely for an allocator hook to be reused for +``PyMem_SetAllocator()`` and ``PyObject_SetAllocator()``, or even +``PyMem_SetRawAllocator()``, but the hook must call a different function +depending on the allocator. The context is a convenient way to reuse the +same custom allocator or hook for different Python allocators. + +In C++, the context can be used to pass *this*. + + +External Libraries +================== + +Examples of API used to customize memory allocators. + +Libraries used by Python: + +* OpenSSL: `CRYPTO_set_mem_functions() + `_ + to set memory management functions globally +* expat: `parserCreate() + `_ + has a per-instance memory handler +* zlib: `zlib 1.2.8 Manual `_, + pass an opaque pointer +* bz2: `bzip2 and libbzip2, version 1.0.5 + `_, + pass an opaque pointer +* lzma: `LZMA SDK - How to Use + `_, + pass an opaque pointer +* lipmpdec: no opaque pointer (classic malloc API) + +Other libraries: + +* glib: `g_mem_set_vtable() + `_ +* libxml2: + `xmlGcMemSetup() `_, + global +* Oracle's OCI: `Oracle Call Interface Programmer's Guide, + Release 2 (9.2) + `_, + pass an opaque pointer + +The new *ctx* parameter of this PEP was inspired by the API of zlib and +Oracle's OCI libraries. + +See also the `GNU libc: Memory Allocation Hooks +`_ +which uses a different approach to hook memory allocators. + + +Memory Allocators +================= + +The C standard library provides the well known ``malloc()`` function. +Its implementation depends on the platform and of the C library. The GNU +C library uses a modified ptmalloc2, based on "Doug Lea's Malloc" +(dlmalloc). FreeBSD uses `jemalloc +`_. Google provides *tcmalloc* which +is part of `gperftools `_. + +``malloc()`` uses two kinds of memory: heap and memory mappings. Memory +mappings are usually used for large allocations (ex: larger than 256 +KB), whereas the heap is used for small allocations. + +On UNIX, the heap is handled by ``brk()`` and ``sbrk()`` system calls, +and it is contiguous. On Windows, the heap is handled by +``HeapAlloc()`` and can be discontiguous. Memory mappings are handled by +``mmap()`` on UNIX and ``VirtualAlloc()`` on Windows, they can be +discontiguous. + +Releasing a memory mapping gives back immediatly the memory to the +system. On UNIX, the heap memory is only given back to the system if the +released block is located at the end of the heap. Otherwise, the memory +will only be given back to the system when all the memory located after +the released memory is also released. + +To allocate memory on the heap, an allocator tries to reuse free space. +If there is no contiguous space big enough, the heap must be enlarged, +even if there is more free space than required size. This issue is +called the "memory fragmentation": the memory usage seen by the system +is higher than real usage. On Windows, ``HeapAlloc()`` creates +a new memory mapping with ``VirtualAlloc()`` if there is not enough free +contiguous memory. + +CPython has a *pymalloc* allocator for allocations smaller than 512 +bytes. This allocator is optimized for small objects with a short +lifetime. It uses memory mappings called "arenas" with a fixed size of +256 KB. + +Other allocators: + +* Windows provides a `Low-fragmentation Heap + `_. + +* The Linux kernel uses `slab allocation + `_. + +* The glib library has a `Memory Slice API + `_: + efficient way to allocate groups of equal-sized chunks of memory + +This PEP allows to choose exactly which memory allocator is used for your +application depending on its usage of the memory (number of allocations, +size of allocations, lifetime of objects, etc.). + + +Links +===== + +CPython issues related to memory allocation: + +* `Issue #3329: Add new APIs to customize memory allocators + `_ +* `Issue #13483: Use VirtualAlloc to allocate memory arenas + `_ +* `Issue #16742: PyOS_Readline drops GIL and calls PyOS_StdioReadline, + which isn't thread safe `_ +* `Issue #18203: Replace calls to malloc() with PyMem_Malloc() or + PyMem_RawMalloc() `_ +* `Issue #18227: Use Python memory allocators in external libraries like + zlib or OpenSSL `_ + +Projects analyzing the memory usage of Python applications: + +* `pytracemalloc + `_ +* `Meliae: Python Memory Usage Analyzer + `_ +* `Guppy-PE: umbrella package combining Heapy and GSL + `_ +* `PySizer (developed for Python 2.4) + `_ + + +Copyright +========= + +This document has been placed into the public domain. + diff --git a/pep-0446.txt b/pep-0446.txt new file mode 100644 --- /dev/null +++ b/pep-0446.txt @@ -0,0 +1,242 @@ +PEP: 446 +Title: Add new parameters to configure the inheritance of files and for non-blocking sockets +Version: $Revision$ +Last-Modified: $Date$ +Author: Victor Stinner +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 3-July-2013 +Python-Version: 3.4 + + +Abstract +======== + +This PEP proposes new portable parameters and functions to configure the +inheritance of file descriptors and the non-blocking flag of sockets. + + +Rationale +========= + +Inheritance of file descriptors +------------------------------- + +The inheritance of file descriptors in child processes can be configured +on each file descriptor using a *close-on-exec* flag. By default, the +close-on-exec flag is not set. + +On Windows, the close-on-exec flag is ``HANDLE_FLAG_INHERIT``. File +descriptors are not inherited if the ``bInheritHandles`` parameter of +the ``CreateProcess()`` function is ``FALSE``, even if the +``HANDLE_FLAG_INHERIT`` flag is set. If ``bInheritHandles`` is ``TRUE``, +only file descriptors with ``HANDLE_FLAG_INHERIT`` flag set are +inherited, others are not. + +On UNIX, the close-on-exec flag is ``O_CLOEXEC``. File descriptors with +the ``O_CLOEXEC`` flag set are closed at the execution of a new program +(ex: when calling ``execv()``). + +The ``O_CLOEXEC`` flag has no effect on ``fork()``, all file descriptors +are inherited by the child process. Futhermore, most properties file +descriptors are shared between the parent and the child processes, +except file attributes which are duplicated (``O_CLOEXEC`` is the only +file attribute). Setting ``O_CLOEXEC`` flag of a file descriptor in the +child process does not change the ``O_CLOEXEC`` flag of the file +descriptor in the parent process. + + +Issues of the inheritance of file descriptors +--------------------------------------------- + +Inheritance of file descriptors causes issues. For example, closing a +file descriptor in the parent process does not release the resource +(file, socket, ...), because the file descriptor is still open in the +child process. + +Leaking file descriptors is also a major security vulnerability. An +untrusted child process can read sensitive data like passwords and take +control of the parent process though leaked file descriptors. It is for +example a known vulnerability to escape from a chroot. + + +Non-blocking sockets +-------------------- + +To handle multiple network clients in a single thread, a multiplexing +function like ``select()`` can be used. For best performances, sockets +must be configured as non-blocking. Operations like ``send()`` and +``recv()`` return an ``EAGAIN`` or ``EWOULDBLOCK`` error if the +operation would block. + +By default, newly created sockets are blocking. Setting the non-blocking +mode requires additional system calls. + +On UNIX, the blocking flag is ``O_NONBLOCK``: a pipe and a socket are +non-blocking if the ``O_NONBLOCK`` flag is set. + + +Setting flags at the creation of the file descriptor +---------------------------------------------------- + +Windows and recent versions of other operating systems like Linux +support setting the close-on-exec flag directly at the creation of file +descriptors, and close-on-exec and blocking flags at the creation of +sockets. + +Setting these flags at the creation is atomic and avoids additional +system calls. + + +Proposal +======== + +New cloexec And blocking Parameters +----------------------------------- + +Add a new optional *cloexec* on functions creating file descriptors: + +* ``io.FileIO`` +* ``io.open()`` +* ``open()`` +* ``os.dup()`` +* ``os.dup2()`` +* ``os.fdopen()`` +* ``os.open()`` +* ``os.openpty()`` +* ``os.pipe()`` +* ``select.devpoll()`` +* ``select.epoll()`` +* ``select.kqueue()`` + +Add new optional *cloexec* and *blocking* parameters to functions +creating sockets: + +* ``asyncore.dispatcher.create_socket()`` +* ``socket.socket()`` +* ``socket.socket.accept()`` +* ``socket.socket.dup()`` +* ``socket.socket.fromfd`` +* ``socket.socketpair()`` + +The default value of *cloexec* is ``False`` and the default value of +*blocking* is ``True``. + +The atomicity is not guaranteed. If the platform does not support +setting close-on-exec and blocking flags at the creation of the file +descriptor or socket, the flags are set using additional system calls. + + +New Functions +------------- + +Add new functions the get and set the close-on-exec flag of a file +descriptor, available on all platforms: + +* ``os.get_cloexec(fd:int) -> bool`` +* ``os.set_cloexec(fd:int, cloexec: bool)`` + +Add new functions the get and set the blocking flag of a file +descriptor, only available on UNIX: + +* ``os.get_blocking(fd:int) -> bool`` +* ``os.set_blocking(fd:int, blocking: bool)`` + + +Other Changes +------------- + +The ``subprocess.Popen`` class must clear the close-on-exec flag of file +descriptors of the ``pass_fds`` parameter. The flag is cleared in the +child process before executing the program, the change does not change +the flag in the parent process. + +The close-on-exec flag must also be set on private file descriptors and +sockets in the Python standard library. For example, on UNIX, +os.urandom() opens ``/dev/urandom`` to read some random bytes and the +file descriptor is closed at function exit. The file descriptor is not +expected to be inherited by child processes. + + +Rejected Alternatives +===================== + +PEP 433 +------- + +The PEP 433 entitled "Easier suppression of file descriptor inheritance" +is a previous attempt proposing various other alternatives, but no +consensus could be reached. + +This PEP has a well defined behaviour (the default value of the new +*cloexec* parameter is not configurable), is more conservative (no +backward compatibility issue), and is much simpler. + + +Add blocking parameter for file descriptors and use Windows overlapped I/O +-------------------------------------------------------------------------- + +Windows supports non-blocking operations on files using an extension of +the Windows API called "Overlapped I/O". Using this extension requires +to modify the Python standard library and applications to pass a +``OVERLAPPED`` structure and an event loop to wait for the completion of +operations. + +This PEP only tries to expose portable flags on file descriptors and +sockets. Supporting overlapped I/O requires an abstraction providing a +high-level and portable API for asynchronous operations on files and +sockets. Overlapped I/O are out of the scope of this PEP. + +UNIX supports non-blocking files, moreover recent versions of operating +systems support setting the non-blocking flag at the creation of a file +descriptor. It would be possible to add a new optional *blocking* +parameter to Python functions creating file descriptors. On Windows, +creating a file descriptor with ``blocking=False`` would raise a +``NotImplementedError``. This behaviour is not acceptable for the ``os`` +module which is designed as a thin wrapper on the C functions of the +operating system. If a platform does not support a function, the +function should not be available on the platform. For example, +the ``os.fork()`` function is not available on Windows. + +For all these reasons, this alternative was rejected. The PEP 3156 +proposes an abstraction for asynchronous I/O supporting non-blocking +files on Windows. + + +Links +===== + +Python issues: + +* `#10115: Support accept4() for atomic setting of flags at socket + creation `_ +* `#12105: open() does not able to set flags, such as O_CLOEXEC + `_ +* `#12107: TCP listening sockets created without FD_CLOEXEC flag + `_ +* `#16850: Add "e" mode to open(): close-and-exec + (O_CLOEXEC) / O_NOINHERIT `_ +* `#16860: Use O_CLOEXEC in the tempfile module + `_ +* `#16946: subprocess: _close_open_fd_range_safe() does not set + close-on-exec flag on Linux < 2.6.23 if O_CLOEXEC is defined + `_ +* `#17070: Use the new cloexec to improve security and avoid bugs + `_ + +Other links: + +* `Secure File Descriptor Handling + `_ (Ulrich Drepper, + 2008) +* `Ghosts of Unix past, part 2: Conflated designs + `_ (Neil Brown, 2010) explains the + history of ``O_CLOEXEC`` and ``O_NONBLOCK`` flags + + +Copyright +========= + +This document has been placed into the public domain. + -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Tue Jul 9 05:47:47 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 09 Jul 2013 05:47:47 +0200 Subject: [Python-checkins] Daily reference leaks (c91e7f707562): sum=0 Message-ID: results for c91e7f707562 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogZuuOHW', '-x'] From python-checkins at python.org Tue Jul 9 09:13:31 2013 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 9 Jul 2013 09:13:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_a_spacing_saving_heuri?= =?utf-8?q?stic_to_deque=27s_extend_methods?= Message-ID: <3bqFB31F10z7Lkw@mail.python.org> http://hg.python.org/cpython/rev/904399fae081 changeset: 84524:904399fae081 user: Raymond Hettinger date: Tue Jul 09 00:13:21 2013 -0700 summary: Add a spacing saving heuristic to deque's extend methods files: Lib/test/test_deque.py | 4 ++-- Modules/_collectionsmodule.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -543,8 +543,8 @@ check = self.check_sizeof check(deque(), basesize + blocksize) check(deque('a'), basesize + blocksize) - check(deque('a' * (BLOCKLEN // 2)), basesize + blocksize) - check(deque('a' * (BLOCKLEN // 2 + 1)), basesize + 2 * blocksize) + check(deque('a' * (BLOCKLEN - 1)), basesize + blocksize) + check(deque('a' * BLOCKLEN), basesize + 2 * blocksize) check(deque('a' * (42 * BLOCKLEN)), basesize + 43 * blocksize) class TestVariousIteratorArgs(unittest.TestCase): diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -332,6 +332,14 @@ return result; } + /* Space saving heuristic. Start filling from the left */ + if (Py_SIZE(deque) == 0) { + assert(deque->leftblock == deque->rightblock); + assert(deque->leftindex == deque->rightindex+1); + deque->leftindex = 1; + deque->rightindex = 0; + } + it = PyObject_GetIter(iterable); if (it == NULL) return NULL; @@ -385,6 +393,14 @@ return result; } + /* Space saving heuristic. Start filling from the right */ + if (Py_SIZE(deque) == 0) { + assert(deque->leftblock == deque->rightblock); + assert(deque->leftindex == deque->rightindex+1); + deque->leftindex = BLOCKLEN - 1; + deque->rightindex = BLOCKLEN - 2; + } + it = PyObject_GetIter(iterable); if (it == NULL) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 14:30:45 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 9 Jul 2013 14:30:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogdXNlICQoTE4pIG1h?= =?utf-8?q?kefile_variable_instead_of_ln?= Message-ID: <3bqND56qwWz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/09f86b4ac1a0 changeset: 84525:09f86b4ac1a0 branch: 3.3 parent: 84505:6f16fa5223cc user: Christian Heimes date: Tue Jul 09 14:30:04 2013 +0200 summary: use $(LN) makefile variable instead of ln files: Makefile.pre.in | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1285,12 +1285,12 @@ # Install a number of symlinks to keep software that expects a normal unix # install (which includes python-config) happy. frameworkinstallmaclib: - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).a" - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).dylib" - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).a" - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).dylib" - ln -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(LDVERSION).dylib" - ln -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(VERSION).dylib" + $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).a" + $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).dylib" + $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).a" + $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).dylib" + $(LN) -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(LDVERSION).dylib" + $(LN) -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(VERSION).dylib" # This installs the IDE, the Launcher and other apps into /Applications frameworkinstallapps: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 14:30:47 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 9 Jul 2013 14:30:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_use_=24=28LN=29_makefile_variable_instead_of_ln?= Message-ID: <3bqND72qQFz7LkZ@mail.python.org> http://hg.python.org/cpython/rev/3f3cbfd52f94 changeset: 84526:3f3cbfd52f94 parent: 84524:904399fae081 parent: 84525:09f86b4ac1a0 user: Christian Heimes date: Tue Jul 09 14:30:22 2013 +0200 summary: use $(LN) makefile variable instead of ln files: Makefile.pre.in | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1287,12 +1287,12 @@ # Install a number of symlinks to keep software that expects a normal unix # install (which includes python-config) happy. frameworkinstallmaclib: - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).a" - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).dylib" - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).a" - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).dylib" - ln -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(LDVERSION).dylib" - ln -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(VERSION).dylib" + $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).a" + $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).dylib" + $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).a" + $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).dylib" + $(LN) -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(LDVERSION).dylib" + $(LN) -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(VERSION).dylib" # This installs the IDE, the Launcher and other apps into /Applications frameworkinstallapps: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 15:27:25 2013 From: python-checkins at python.org (barry.warsaw) Date: Tue, 9 Jul 2013 15:27:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Clarify_the_wording=2E?= Message-ID: <3bqPTT00nFz7LkF@mail.python.org> http://hg.python.org/peps/rev/c6a5738d5eb3 changeset: 4989:c6a5738d5eb3 user: Barry Warsaw date: Tue Jul 09 09:27:16 2013 -0400 summary: Clarify the wording. files: pep-0008.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -101,7 +101,8 @@ var_three, var_four) The closing brace/bracket/parenthesis on multi-line constructs may -either line up under the last item of the list, as in:: +either line up under the first non-whitespace character of the last +line of list, as in:: my_list = [ 1, 2, 3, -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jul 9 19:17:29 2013 From: python-checkins at python.org (charles-francois.natali) Date: Tue, 9 Jul 2013 19:17:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzA4?= =?utf-8?q?=3A_don=27t_take_the_scope_ID_into_account_when_comparing_IPv6?= Message-ID: <3bqVZx73TBz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/330c7aa2922b changeset: 84527:330c7aa2922b branch: 3.3 parent: 84525:09f86b4ac1a0 user: Charles-Fran?ois Natali date: Tue Jul 09 19:15:43 2013 +0200 summary: Issue #18308: don't take the scope ID into account when comparing IPv6 addresses. files: Lib/test/test_socket.py | 6 +++++- 1 files changed, 5 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 @@ -3225,7 +3225,11 @@ class SendrecvmsgUDP6TestBase(SendrecvmsgDgramFlagsBase, SendrecvmsgConnectionlessBase, ThreadedSocketTestMixin, UDP6TestBase): - pass + + def checkRecvmsgAddress(self, addr1, addr2): + # Called to compare the received address with the address of + # the peer, ignoring scope ID + self.assertEqual(addr1[:-1], addr2[:-1]) @requireAttrs(socket.socket, "sendmsg") @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 9 19:17:31 2013 From: python-checkins at python.org (charles-francois.natali) Date: Tue, 9 Jul 2013 19:17:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318308=3A_don=27t_take_the_scope_ID_into_account?= =?utf-8?q?_when_comparing_IPv6?= Message-ID: <3bqVZz3BBsz7LkX@mail.python.org> http://hg.python.org/cpython/rev/b44749cee660 changeset: 84528:b44749cee660 parent: 84526:3f3cbfd52f94 parent: 84527:330c7aa2922b user: Charles-Fran?ois Natali date: Tue Jul 09 19:16:32 2013 +0200 summary: Issue #18308: don't take the scope ID into account when comparing IPv6 addresses. files: Lib/test/test_socket.py | 6 +++++- 1 files changed, 5 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 @@ -3312,7 +3312,11 @@ class SendrecvmsgUDP6TestBase(SendrecvmsgDgramFlagsBase, SendrecvmsgConnectionlessBase, ThreadedSocketTestMixin, UDP6TestBase): - pass + + def checkRecvmsgAddress(self, addr1, addr2): + # Called to compare the received address with the address of + # the peer, ignoring scope ID + self.assertEqual(addr1[:-1], addr2[:-1]) @requireAttrs(socket.socket, "sendmsg") @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 10 05:02:05 2013 From: python-checkins at python.org (richard.jones) Date: Wed, 10 Jul 2013 05:02:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_clarify_CA_cert_issue=3B_inst?= =?utf-8?q?all_virtualenv_as_well=3B_mention_Python_2=2E7?= Message-ID: <3bqlYT3PDBz7Ljd@mail.python.org> http://hg.python.org/peps/rev/bd9b2df92af5 changeset: 4990:bd9b2df92af5 user: Richard Jones date: Wed Jul 10 13:01:57 2013 +1000 summary: clarify CA cert issue; install virtualenv as well; mention Python 2.7 possibility files: pep-0439.txt | 34 ++++++++++++++++++++++++---------- 1 files changed, 24 insertions(+), 10 deletions(-) diff --git a/pep-0439.txt b/pep-0439.txt --- a/pep-0439.txt +++ b/pep-0439.txt @@ -45,6 +45,12 @@ considerably reduced. It is hoped that this will therefore increase the likelihood that Python projects will reuse third party software. +The Python community also has an issue of complexity around the current +bootstrap procedure for pip, setuptools and virtualenv. They all have +their own bootstrap download file with slightly different usages and +even refer to each other in some cases. Having a single bootstrap which +is common amongst them all, with a simple usage, would be far preferable. + It is also hoped that this is reduces the number of proposals to include more and more software in the Python standard library, and therefore that more popular Python software is more easily upgradeable @@ -54,6 +60,9 @@ Proposal ======== +The bootstrap will install the pip implementation, setuptools and virtualenv +by downloading their installation files from PyPI. + This proposal affects two components of packaging: `the pip bootstrap`_ and, thanks to easier package installation, `modifications to publishing packages`_. @@ -68,11 +77,11 @@ The Python installation includes an executable called "pip3" (see PEP 394 for naming rationale etc.) that attempts to import pip machinery. If it can then the pip command proceeds as normal. If it cannot it will bootstrap pip by -downloading the pip implementation and setuptools wheel files. Hereafter the -installation of the "pip implementation" will imply installation of -setuptools. Once installed, the pip command proceeds as normal. Once the -bootstrap process is complete the "pip3" command is no longer the bootstrap -but rather the full pip command. +downloading the pip implementation, setuptools and virtualenv wheel files. +Hereafter the installation of the "pip implementation" will imply installation +of setuptools and virtualenv. Once installed, the pip command proceeds as +normal. Once the bootstrap process is complete the "pip3" command is no longer +the bootstrap but rather the full pip command. A boostrap is used in the place of a the full pip code so that we don't have to bundle pip and also pip is upgradeable outside of the regular Python @@ -114,12 +123,13 @@ Some users may have no Internet access suitable for fetching the pip implementation file. These users can manually download and install the -setuptools and pip tar files. Adding specific support for this use-case is -unnecessary. +setuptools, virtualenv and pip tar files. Adding specific support for this +use-case is unnecessary. The download of the pip implementation install file will be performed securely. The transport from pypi.python.org will be done over HTTPS with the -CA certificate check performed (see PEP XXXX). +CA certificate check performed. This facility will be present in Python 3.4+ +using Operating System certificates (see PEP XXXX). Beyond those arguments controlling index location and download options, the "pip3" boostrap command may support further standard pip @@ -173,13 +183,17 @@ issue tracker [2]_. Most notably, the addition of --bootstrap and --bootstrap- to-system to the pip command-line. +It would be preferable that the pip, setuptools and virtualenv projects +distribute a wheel format download. + The required code for this implementation is the "pip3" command described above. The additional pypublish can be developed outside of the scope of this PEP's work. Finally, it would be desirable that "pip3" be ported to Python 2.6+ to allow -the single command to replace all existing pip/setuptools/distribute and -possibly virtualenv bootstrap scripts. +the single command to replace all existing pip, setuptools and virtualenv +bootstrap scripts. Having that bootstrap included in a future Python 2.7 +release would also be highly desirable. Risks -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Wed Jul 10 05:46:46 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 10 Jul 2013 05:46:46 +0200 Subject: [Python-checkins] Daily reference leaks (b44749cee660): sum=0 Message-ID: results for b44749cee660 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog2WC8Iu', '-x'] From python-checkins at python.org Wed Jul 10 07:07:51 2013 From: python-checkins at python.org (richard.jones) Date: Wed, 10 Jul 2013 07:07:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_remove_virtualenv_from_the_pi?= =?utf-8?q?p3_install?= Message-ID: <3bqpLb5Q3dz7LjX@mail.python.org> http://hg.python.org/peps/rev/c40ed3544492 changeset: 4991:c40ed3544492 user: Richard Jones date: Wed Jul 10 15:07:43 2013 +1000 summary: remove virtualenv from the pip3 install files: pep-0439.txt | 30 +++++++++++++++--------------- 1 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pep-0439.txt b/pep-0439.txt --- a/pep-0439.txt +++ b/pep-0439.txt @@ -46,7 +46,7 @@ the likelihood that Python projects will reuse third party software. The Python community also has an issue of complexity around the current -bootstrap procedure for pip, setuptools and virtualenv. They all have +bootstrap procedure for pip and setuptools. They all have their own bootstrap download file with slightly different usages and even refer to each other in some cases. Having a single bootstrap which is common amongst them all, with a simple usage, would be far preferable. @@ -60,8 +60,8 @@ Proposal ======== -The bootstrap will install the pip implementation, setuptools and virtualenv -by downloading their installation files from PyPI. +The bootstrap will install the pip implementation, setuptools by downloading +their installation files from PyPI. This proposal affects two components of packaging: `the pip bootstrap`_ and, thanks to easier package installation, `modifications to publishing @@ -77,11 +77,11 @@ The Python installation includes an executable called "pip3" (see PEP 394 for naming rationale etc.) that attempts to import pip machinery. If it can then the pip command proceeds as normal. If it cannot it will bootstrap pip by -downloading the pip implementation, setuptools and virtualenv wheel files. -Hereafter the installation of the "pip implementation" will imply installation -of setuptools and virtualenv. Once installed, the pip command proceeds as -normal. Once the bootstrap process is complete the "pip3" command is no longer -the bootstrap but rather the full pip command. +downloading the pip implementation and setuptools wheel files. Hereafter the +installation of the "pip implementation" will imply installation of setuptools +and virtualenv. Once installed, the pip command proceeds as normal. Once the +bootstrap process is complete the "pip3" command is no longer the bootstrap +but rather the full pip command. A boostrap is used in the place of a the full pip code so that we don't have to bundle pip and also pip is upgradeable outside of the regular Python @@ -123,8 +123,8 @@ Some users may have no Internet access suitable for fetching the pip implementation file. These users can manually download and install the -setuptools, virtualenv and pip tar files. Adding specific support for this -use-case is unnecessary. +setuptools and pip tar files. Adding specific support for this use-case is +unnecessary. The download of the pip implementation install file will be performed securely. The transport from pypi.python.org will be done over HTTPS with the @@ -183,17 +183,17 @@ issue tracker [2]_. Most notably, the addition of --bootstrap and --bootstrap- to-system to the pip command-line. -It would be preferable that the pip, setuptools and virtualenv projects -distribute a wheel format download. +It would be preferable that the pip and setuptools projects distribute a wheel +format download. The required code for this implementation is the "pip3" command described above. The additional pypublish can be developed outside of the scope of this PEP's work. Finally, it would be desirable that "pip3" be ported to Python 2.6+ to allow -the single command to replace all existing pip, setuptools and virtualenv -bootstrap scripts. Having that bootstrap included in a future Python 2.7 -release would also be highly desirable. +the single command to replace existing pip, setuptools and virtualenv (which +would be added to the bootstrap) bootstrap scripts. Having that bootstrap +included in a future Python 2.7 release would also be highly desirable. Risks -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jul 10 14:04:13 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 10 Jul 2013 14:04:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_call?= =?utf-8?q?=5Fexc=5Ftrace=28=29=3A_if_the_traceback_is_NULL=2C_use_None_wh?= =?utf-8?q?en?= Message-ID: <3bqzb14Ntzz7LnW@mail.python.org> http://hg.python.org/cpython/rev/4f730c045f5f changeset: 84529:4f730c045f5f user: Victor Stinner date: Wed Jul 10 13:57:55 2013 +0200 summary: Issue #18408: Fix call_exc_trace(): if the traceback is NULL, use None when building the tuple (type, value, traceback) passed to the callback. PyTuple_Pack() does crash if an argument is NULL. files: Python/ceval.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3817,7 +3817,7 @@ static void call_exc_trace(Py_tracefunc func, PyObject *self, PyFrameObject *f) { - PyObject *type, *value, *traceback, *arg; + PyObject *type, *value, *traceback, *orig_traceback, *arg; int err; PyErr_Fetch(&type, &value, &traceback); if (value == NULL) { @@ -3825,6 +3825,11 @@ Py_INCREF(value); } PyErr_NormalizeException(&type, &value, &traceback); + orig_traceback = traceback; + if (traceback == NULL) { + Py_INCREF(Py_None); + traceback = Py_None; + } arg = PyTuple_Pack(3, type, value, traceback); if (arg == NULL) { PyErr_Restore(type, value, traceback); @@ -3833,11 +3838,11 @@ err = call_trace(func, self, f, PyTrace_EXCEPTION, arg); Py_DECREF(arg); if (err == 0) - PyErr_Restore(type, value, traceback); + PyErr_Restore(type, value, orig_traceback); else { Py_XDECREF(type); Py_XDECREF(value); - Py_XDECREF(traceback); + Py_XDECREF(orig_traceback); } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 10 17:59:21 2013 From: python-checkins at python.org (r.david.murray) Date: Wed, 10 Jul 2013 17:59:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4Mzk5OiBmaXgg?= =?utf-8?q?comment_typo=2E?= Message-ID: <3br4pK1cGNz7Lkt@mail.python.org> http://hg.python.org/cpython/rev/c02656962b9c changeset: 84530:c02656962b9c branch: 3.3 parent: 84527:330c7aa2922b user: R David Murray date: Wed Jul 10 10:57:39 2013 -0400 summary: #18399: fix comment typo. Patch by Andrew Rowe. files: Modules/python.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/python.c b/Modules/python.c --- a/Modules/python.c +++ b/Modules/python.c @@ -19,7 +19,7 @@ main(int argc, char **argv) { wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); - /* We need a second copies, as Python might modify the first one. */ + /* We need a second copy, as Python might modify the first one. */ wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); int i, res; char *oldloc; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 10 17:59:22 2013 From: python-checkins at python.org (r.david.murray) Date: Wed, 10 Jul 2013 17:59:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_=2318399=3A_fix_comment_typo=2E?= Message-ID: <3br4pL3q8Hz7LkH@mail.python.org> http://hg.python.org/cpython/rev/b583fd54c8d6 changeset: 84531:b583fd54c8d6 parent: 84529:4f730c045f5f parent: 84530:c02656962b9c user: R David Murray date: Wed Jul 10 11:57:39 2013 -0400 summary: Merge: #18399: fix comment typo. files: Modules/python.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/python.c b/Modules/python.c --- a/Modules/python.c +++ b/Modules/python.c @@ -19,7 +19,7 @@ main(int argc, char **argv) { wchar_t **argv_copy; - /* We need a second copies, as Python might modify the first one. */ + /* We need a second copy, as Python might modify the first one. */ wchar_t **argv_copy2; int i, res; char *oldloc; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 10 22:23:47 2013 From: python-checkins at python.org (r.david.murray) Date: Wed, 10 Jul 2013 22:23:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4NDI0OiBQRVA4?= =?utf-8?q?ify_the_tense_of_the_sum_docstring=2E?= Message-ID: <3brBgR5zTDz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/4b3b87719e2c changeset: 84532:4b3b87719e2c branch: 3.3 parent: 84530:c02656962b9c user: R David Murray date: Wed Jul 10 16:22:14 2013 -0400 summary: #18424: PEP8ify the tense of the sum docstring. files: Python/bltinmodule.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2097,9 +2097,9 @@ PyDoc_STRVAR(sum_doc, "sum(iterable[, start]) -> value\n\ \n\ -Returns the sum of an iterable of numbers (NOT strings) plus the value\n\ +Return the sum of an iterable of numbers (NOT strings) plus the value\n\ of parameter 'start' (which defaults to 0). When the iterable is\n\ -empty, returns start."); +empty, return start."); static PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 10 22:23:49 2013 From: python-checkins at python.org (r.david.murray) Date: Wed, 10 Jul 2013 22:23:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_=2318424=3A_PEP8ify_the_tense_of_the_sum_docstr?= =?utf-8?q?ing=2E?= Message-ID: <3brBgT187Xz7Lk5@mail.python.org> http://hg.python.org/cpython/rev/38b42ffdf86b changeset: 84533:38b42ffdf86b parent: 84531:b583fd54c8d6 parent: 84532:4b3b87719e2c user: R David Murray date: Wed Jul 10 16:22:59 2013 -0400 summary: Merge: #18424: PEP8ify the tense of the sum docstring. files: Python/bltinmodule.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2113,9 +2113,9 @@ PyDoc_STRVAR(sum_doc, "sum(iterable[, start]) -> value\n\ \n\ -Returns the sum of an iterable of numbers (NOT strings) plus the value\n\ +Return the sum of an iterable of numbers (NOT strings) plus the value\n\ of parameter 'start' (which defaults to 0). When the iterable is\n\ -empty, returns start."); +empty, return start."); static PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 10 22:23:50 2013 From: python-checkins at python.org (r.david.murray) Date: Wed, 10 Jul 2013 22:23:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE4NDI0OiBQRVA4?= =?utf-8?q?ify_the_tense_of_the_sum_docstring=2E?= Message-ID: <3brBgV3M98z7LlQ@mail.python.org> http://hg.python.org/cpython/rev/c5f5b5e89a94 changeset: 84534:c5f5b5e89a94 branch: 2.7 parent: 84478:5d41ebc79738 user: R David Murray date: Wed Jul 10 16:23:15 2013 -0400 summary: #18424: PEP8ify the tense of the sum docstring. files: Python/bltinmodule.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2434,9 +2434,9 @@ PyDoc_STRVAR(sum_doc, "sum(sequence[, start]) -> value\n\ \n\ -Returns the sum of a sequence of numbers (NOT strings) plus the value\n\ +Return the sum of a sequence of numbers (NOT strings) plus the value\n\ of parameter 'start' (which defaults to 0). When the sequence is\n\ -empty, returns start."); +empty, return start."); static PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 10 23:10:44 2013 From: python-checkins at python.org (r.david.murray) Date: Wed, 10 Jul 2013 23:10:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2318116=3A_getpass_no_lon?= =?utf-8?q?ger_always_falls_back_to_stdin=2E?= Message-ID: <3brCjc3TyXz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/70f55dc9d43f changeset: 84535:70f55dc9d43f parent: 84533:38b42ffdf86b user: R David Murray date: Wed Jul 10 17:02:24 2013 -0400 summary: #18116: getpass no longer always falls back to stdin. Also fixes a resource warning that occurred when the fallback is taken. Patch by Serhiy Storchaka. (We couldn't figure out how to write tests for this.) files: Lib/getpass.py | 94 +++++++++++++++------------ Lib/test/test_getpass.py | 20 +++-- Misc/NEWS | 4 + 3 files changed, 68 insertions(+), 50 deletions(-) diff --git a/Lib/getpass.py b/Lib/getpass.py --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -15,7 +15,11 @@ # Guido van Rossum (Windows support and cleanup) # Gregory P. Smith (tty support & GetPassWarning) -import os, sys, warnings +import contextlib +import io +import os +import sys +import warnings __all__ = ["getpass","getuser","GetPassWarning"] @@ -38,53 +42,57 @@ Always restores terminal settings before returning. """ - fd = None - tty = None passwd = None - try: - # Always try reading and writing directly on the tty first. - fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY) - tty = os.fdopen(fd, 'w+', 1) - input = tty - if not stream: - stream = tty - except OSError as e: - # If that fails, see if stdin can be controlled. + with contextlib.ExitStack() as stack: try: - fd = sys.stdin.fileno() - except (AttributeError, ValueError): - passwd = fallback_getpass(prompt, stream) - input = sys.stdin - if not stream: - stream = sys.stderr + # Always try reading and writing directly on the tty first. + fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY) + tty = io.FileIO(fd, 'w+') + stack.enter_context(tty) + input = io.TextIOWrapper(tty) + stack.enter_context(input) + if not stream: + stream = input + except OSError as e: + # If that fails, see if stdin can be controlled. + stack.close() + try: + fd = sys.stdin.fileno() + except (AttributeError, ValueError): + fd = None + passwd = fallback_getpass(prompt, stream) + input = sys.stdin + if not stream: + stream = sys.stderr - if fd is not None: - passwd = None - try: - old = termios.tcgetattr(fd) # a copy to save - new = old[:] - new[3] &= ~termios.ECHO # 3 == 'lflags' - tcsetattr_flags = termios.TCSAFLUSH - if hasattr(termios, 'TCSASOFT'): - tcsetattr_flags |= termios.TCSASOFT + if fd is not None: try: - termios.tcsetattr(fd, tcsetattr_flags, new) - passwd = _raw_input(prompt, stream, input=input) - finally: - termios.tcsetattr(fd, tcsetattr_flags, old) - stream.flush() # issue7208 - except termios.error: - if passwd is not None: - # _raw_input succeeded. The final tcsetattr failed. Reraise - # instead of leaving the terminal in an unknown state. - raise - # We can't control the tty or stdin. Give up and use normal IO. - # fallback_getpass() raises an appropriate warning. - del input, tty # clean up unused file objects before blocking - passwd = fallback_getpass(prompt, stream) + old = termios.tcgetattr(fd) # a copy to save + new = old[:] + new[3] &= ~termios.ECHO # 3 == 'lflags' + tcsetattr_flags = termios.TCSAFLUSH + if hasattr(termios, 'TCSASOFT'): + tcsetattr_flags |= termios.TCSASOFT + try: + termios.tcsetattr(fd, tcsetattr_flags, new) + passwd = _raw_input(prompt, stream, input=input) + finally: + termios.tcsetattr(fd, tcsetattr_flags, old) + stream.flush() # issue7208 + except termios.error: + if passwd is not None: + # _raw_input succeeded. The final tcsetattr failed. Reraise + # instead of leaving the terminal in an unknown state. + raise + # We can't control the tty or stdin. Give up and use normal IO. + # fallback_getpass() raises an appropriate warning. + if stream is not input: + # clean up unused file objects before blocking + stack.close() + passwd = fallback_getpass(prompt, stream) - stream.write('\n') - return passwd + stream.write('\n') + return passwd def win_getpass(prompt='Password: ', stream=None): diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -1,7 +1,7 @@ import getpass import os import unittest -from io import StringIO +from io import BytesIO, StringIO from unittest import mock from test import support @@ -88,7 +88,8 @@ def test_uses_tty_directly(self): with mock.patch('os.open') as open, \ - mock.patch('os.fdopen'): + mock.patch('io.FileIO') as fileio, \ + mock.patch('io.TextIOWrapper') as textio: # By setting open's return value to None the implementation will # skip code we don't care about in this test. We can mock this out # fully if an alternate implementation works differently. @@ -96,10 +97,13 @@ getpass.unix_getpass() open.assert_called_once_with('/dev/tty', os.O_RDWR | os.O_NOCTTY) + fileio.assert_called_once_with(open.return_value, 'w+') + textio.assert_called_once_with(fileio.return_value) def test_resets_termios(self): with mock.patch('os.open') as open, \ - mock.patch('os.fdopen'), \ + mock.patch('io.FileIO'), \ + mock.patch('io.TextIOWrapper'), \ mock.patch('termios.tcgetattr') as tcgetattr, \ mock.patch('termios.tcsetattr') as tcsetattr: open.return_value = 3 @@ -110,21 +114,23 @@ def test_falls_back_to_fallback_if_termios_raises(self): with mock.patch('os.open') as open, \ - mock.patch('os.fdopen') as fdopen, \ + mock.patch('io.FileIO') as fileio, \ + mock.patch('io.TextIOWrapper') as textio, \ mock.patch('termios.tcgetattr'), \ mock.patch('termios.tcsetattr') as tcsetattr, \ mock.patch('getpass.fallback_getpass') as fallback: open.return_value = 3 - fdopen.return_value = StringIO() + fileio.return_value = BytesIO() tcsetattr.side_effect = termios.error getpass.unix_getpass() fallback.assert_called_once_with('Password: ', - fdopen.return_value) + textio.return_value) def test_flushes_stream_after_input(self): # issue 7208 with mock.patch('os.open') as open, \ - mock.patch('os.fdopen'), \ + mock.patch('io.FileIO'), \ + mock.patch('io.TextIOWrapper'), \ mock.patch('termios.tcgetattr'), \ mock.patch('termios.tcsetattr'): open.return_value = 3 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -142,6 +142,10 @@ Library ------- +- Issue #18116: getpass was always getting an error when testing /dev/tty, + and thus was always falling back to stdin. It also leaked an open file + when it did so. Both of these issues are now fixed. + - Issue #17198: Fix a NameError in the dbm module. Patch by Valentina Mukhamedzhanova. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jul 11 05:47:28 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 11 Jul 2013 05:47:28 +0200 Subject: [Python-checkins] Daily reference leaks (70f55dc9d43f): sum=-1 Message-ID: results for 70f55dc9d43f 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/reflogUSE_86', '-x'] From python-checkins at python.org Thu Jul 11 11:24:13 2013 From: python-checkins at python.org (christian.heimes) Date: Thu, 11 Jul 2013 11:24:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDI2?= =?utf-8?q?=3A_Fix_NULL_pointer_dereference_in_C_extension_import_when?= Message-ID: <3brWzx3w0lz7Lls@mail.python.org> http://hg.python.org/cpython/rev/4343dfaca8e2 changeset: 84536:4343dfaca8e2 branch: 3.3 parent: 84532:4b3b87719e2c user: Christian Heimes date: Thu Jul 11 11:22:21 2013 +0200 summary: Issue #18426: Fix NULL pointer dereference in C extension import when PyModule_GetDef() returns an error. files: Misc/NEWS | 3 +++ Python/importdl.c | 2 ++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #18426: Fix NULL pointer dereference in C extension import when + PyModule_GetDef() returns an error. + - Issue #18328: Reorder ops in PyThreadState_Delete*() functions. Now the tstate is first removed from TLS and then deallocated. diff --git a/Python/importdl.c b/Python/importdl.c --- a/Python/importdl.c +++ b/Python/importdl.c @@ -97,6 +97,8 @@ /* Remember pointer to module init function. */ def = PyModule_GetDef(m); + if (def == NULL) + goto error; def->m_base.m_init = p; /* Remember the filename as the __file__ attribute */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 11:24:14 2013 From: python-checkins at python.org (christian.heimes) Date: Thu, 11 Jul 2013 11:24:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318426=3A_Fix_NULL_pointer_dereference_in_C_exte?= =?utf-8?q?nsion_import_when?= Message-ID: <3brWzy6DVZz7Lln@mail.python.org> http://hg.python.org/cpython/rev/9fb3656b178a changeset: 84537:9fb3656b178a parent: 84535:70f55dc9d43f parent: 84536:4343dfaca8e2 user: Christian Heimes date: Thu Jul 11 11:23:34 2013 +0200 summary: Issue #18426: Fix NULL pointer dereference in C extension import when PyModule_GetDef() returns an error. files: Misc/NEWS | 3 +++ Python/importdl.c | 2 ++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18426: Fix NULL pointer dereference in C extension import when + PyModule_GetDef() returns an error. + - Issue #17206: On Windows, increase the stack size from 2 MB to 4.2 MB to fix a stack overflow in the marshal module (fix a crash in test_marshal). Patch written by Jeremy Kloth. diff --git a/Python/importdl.c b/Python/importdl.c --- a/Python/importdl.c +++ b/Python/importdl.c @@ -97,6 +97,8 @@ /* Remember pointer to module init function. */ def = PyModule_GetDef(m); + if (def == NULL) + goto error; def->m_base.m_init = p; /* Remember the filename as the __file__ attribute */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 13:03:47 2013 From: python-checkins at python.org (christian.heimes) Date: Thu, 11 Jul 2013 13:03:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDI2?= =?utf-8?q?=3A_improve_exception_message=2E_Courtesy_of_Amaury?= Message-ID: <3brZBq6R43zR9k@mail.python.org> http://hg.python.org/cpython/rev/fce581643cb6 changeset: 84538:fce581643cb6 branch: 3.3 parent: 84536:4343dfaca8e2 user: Christian Heimes date: Thu Jul 11 13:02:30 2013 +0200 summary: Issue #18426: improve exception message. Courtesy of Amaury files: Python/importdl.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Python/importdl.c b/Python/importdl.c --- a/Python/importdl.c +++ b/Python/importdl.c @@ -97,8 +97,12 @@ /* Remember pointer to module init function. */ def = PyModule_GetDef(m); - if (def == NULL) + if (def == NULL) { + PyErr_Format(PyExc_SystemError, + "initialization of %s did not return an extension " + "module", shortname); goto error; + } def->m_base.m_init = p; /* Remember the filename as the __file__ attribute */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 13:03:49 2013 From: python-checkins at python.org (christian.heimes) Date: Thu, 11 Jul 2013 13:03:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318426=3A_improve_exception_message=2E_Courtesy_?= =?utf-8?q?of_Amaury?= Message-ID: <3brZBs1czvzRJm@mail.python.org> http://hg.python.org/cpython/rev/7a50d3c0aa61 changeset: 84539:7a50d3c0aa61 parent: 84537:9fb3656b178a parent: 84538:fce581643cb6 user: Christian Heimes date: Thu Jul 11 13:02:37 2013 +0200 summary: Issue #18426: improve exception message. Courtesy of Amaury files: Python/importdl.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Python/importdl.c b/Python/importdl.c --- a/Python/importdl.c +++ b/Python/importdl.c @@ -97,8 +97,12 @@ /* Remember pointer to module init function. */ def = PyModule_GetDef(m); - if (def == NULL) + if (def == NULL) { + PyErr_Format(PyExc_SystemError, + "initialization of %s did not return an extension " + "module", shortname); goto error; + } def->m_base.m_init = p; /* Remember the filename as the __file__ attribute */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 13:35:29 2013 From: python-checkins at python.org (ronald.oussoren) Date: Thu, 11 Jul 2013 13:35:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDI3?= =?utf-8?q?=3A_str=2Ereplace_could_crash_the_interpreter_with_huge_strings?= =?utf-8?q?=2E?= Message-ID: <3brZvP33hvzRPr@mail.python.org> http://hg.python.org/cpython/rev/2921f6c2009e changeset: 84540:2921f6c2009e branch: 2.7 parent: 84534:c5f5b5e89a94 user: Ronald Oussoren date: Thu Jul 11 13:33:55 2013 +0200 summary: Issue #18427: str.replace could crash the interpreter with huge strings. This fixes two places where 'int' was used to represent the size of strings, instead of 'Py_ssize_t'. (The issue is not present in the corresponding code in the 3.x branches) Fixes #18427 files: Misc/NEWS | 4 +++- Objects/stringobject.c | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #18427: str.replace could crash the interpreter with huge strings. + - Issue #18347: ElementTree's html serializer now preserves the case of closing tags. @@ -88,7 +90,7 @@ - Issue #7136: In the Idle File menu, "New Window" is renamed "New File". Patch by Tal Einat, Roget Serwy, and Todd Rovito. - + - Issue #8515: Set __file__ when run file in IDLE. Initial patch by Bruce Frederiksen. diff --git a/Objects/stringobject.c b/Objects/stringobject.c --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -882,9 +882,9 @@ size -= chunk_size; } #ifdef __VMS - if (size) fwrite(data, (int)size, 1, fp); + if (size) fwrite(data, (size_t)size, 1, fp); #else - fwrite(data, 1, (int)size, fp); + fwrite(data, 1, (size_t)size, fp); #endif Py_END_ALLOW_THREADS return 0; @@ -2332,7 +2332,7 @@ } Py_LOCAL_INLINE(Py_ssize_t) -countchar(const char *target, int target_len, char c, Py_ssize_t maxcount) +countchar(const char *target, Py_ssize_t target_len, char c, Py_ssize_t maxcount) { Py_ssize_t count=0; const char *start=target; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 17:33:27 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 17:33:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MzM2?= =?utf-8?q?=2E_Fix_a_link_to_StreamReader=27s_read=28=29_method=2E?= Message-ID: <3brh9z2vfSz7LjY@mail.python.org> http://hg.python.org/cpython/rev/7e186bb1642c changeset: 84541:7e186bb1642c branch: 2.7 parent: 84451:328781ae35d2 user: Serhiy Storchaka date: Thu Jul 11 18:25:19 2013 +0300 summary: Issue #18336. Fix a link to StreamReader's read() method. files: Doc/library/codecs.rst | 2 +- 1 files changed, 1 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 @@ -653,7 +653,7 @@ Read one line from the input stream and return the decoded data. *size*, if given, is passed as size argument to the stream's - :meth:`readline` method. + :meth:`read` method. If *keepends* is false line-endings will be stripped from the lines returned. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 17:33:28 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 17:33:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzM2?= =?utf-8?q?=2E_Fix_a_link_to_StreamReader=27s_read=28=29_method=2E?= Message-ID: <3brhB05GpNz7LjY@mail.python.org> http://hg.python.org/cpython/rev/8dd67c20cab7 changeset: 84542:8dd67c20cab7 branch: 3.3 parent: 84538:fce581643cb6 user: Serhiy Storchaka date: Thu Jul 11 18:26:13 2013 +0300 summary: Issue #18336. Fix a link to StreamReader's read() method. files: Doc/library/codecs.rst | 2 +- 1 files changed, 1 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 @@ -694,7 +694,7 @@ Read one line from the input stream and return the decoded data. *size*, if given, is passed as size argument to the stream's - :meth:`readline` method. + :meth:`read` method. If *keepends* is false line-endings will be stripped from the lines returned. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 17:33:30 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 17:33:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318336=2E_Fix_a_link_to_StreamReader=27s_read=28?= =?utf-8?b?KSBtZXRob2Qu?= Message-ID: <3brhB20pqrz7LmB@mail.python.org> http://hg.python.org/cpython/rev/a53ac166fa58 changeset: 84543:a53ac166fa58 parent: 84539:7a50d3c0aa61 parent: 84542:8dd67c20cab7 user: Serhiy Storchaka date: Thu Jul 11 18:27:20 2013 +0300 summary: Issue #18336. Fix a link to StreamReader's read() method. files: Doc/library/codecs.rst | 2 +- 1 files changed, 1 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 @@ -694,7 +694,7 @@ Read one line from the input stream and return the decoded data. *size*, if given, is passed as size argument to the stream's - :meth:`readline` method. + :meth:`read` method. If *keepends* is false line-endings will be stripped from the lines returned. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 17:33:31 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 17:33:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_Merge_heads?= Message-ID: <3brhB368cFz7LkL@mail.python.org> http://hg.python.org/cpython/rev/7d75fe8b3210 changeset: 84544:7d75fe8b3210 branch: 2.7 parent: 84541:7e186bb1642c parent: 84540:2921f6c2009e user: Serhiy Storchaka date: Thu Jul 11 18:28:35 2013 +0300 summary: Merge heads files: Mac/PythonLauncher/FileSettings.h | 5 - Mac/PythonLauncher/FileSettings.m | 46 ++--- Mac/PythonLauncher/MyAppDelegate.m | 6 +- Mac/PythonLauncher/MyDocument.m | 22 +- Mac/PythonLauncher/PreferencesWindowController.m | 23 +- Mac/PythonLauncher/doscript.h | 2 +- Mac/PythonLauncher/doscript.m | 78 +++++----- Mac/PythonLauncher/main.m | 4 +- Misc/NEWS | 10 +- Objects/stringobject.c | 6 +- Python/bltinmodule.c | 4 +- 11 files changed, 98 insertions(+), 108 deletions(-) diff --git a/Mac/PythonLauncher/FileSettings.h b/Mac/PythonLauncher/FileSettings.h --- a/Mac/PythonLauncher/FileSettings.h +++ b/Mac/PythonLauncher/FileSettings.h @@ -45,18 +45,13 @@ + (id)getFactorySettingsForFileType: (NSString *)filetype; + (id)newSettingsForFileType: (NSString *)filetype; -//- (id)init; - (id)initForFileType: (NSString *)filetype; - (id)initForFSDefaultFileType: (NSString *)filetype; - (id)initForDefaultFileType: (NSString *)filetype; -//- (id)initWithFileSettings: (FileSettings *)source; - (void)updateFromSource: (id )source; - (NSString *)commandLineForScript: (NSString *)script; -//- (void)applyFactorySettingsForFileType: (NSString *)filetype; -//- (void)saveDefaults; -//- (void)applyUserDefaults: (NSString *)filetype; - (void)applyValuesFromDict: (NSDictionary *)dict; - (void)reset; - (NSArray *) interpreters; diff --git a/Mac/PythonLauncher/FileSettings.m b/Mac/PythonLauncher/FileSettings.m --- a/Mac/PythonLauncher/FileSettings.m +++ b/Mac/PythonLauncher/FileSettings.m @@ -14,7 +14,7 @@ { static FileSettings *fsdefault_py, *fsdefault_pyw, *fsdefault_pyc; FileSettings **curdefault; - + if ([filetype isEqualToString: @"Python Script"]) { curdefault = &fsdefault_py; } else if ([filetype isEqualToString: @"Python GUI Script"]) { @@ -36,7 +36,7 @@ { static FileSettings *default_py, *default_pyw, *default_pyc; FileSettings **curdefault; - + if ([filetype isEqualToString: @"Python Script"]) { curdefault = &default_py; } else if ([filetype isEqualToString: @"Python GUI Script"]) { @@ -57,7 +57,7 @@ + (id)newSettingsForFileType: (NSString *)filetype { FileSettings *cur; - + cur = [FileSettings new]; [cur initForFileType: filetype]; return [cur retain]; @@ -67,7 +67,7 @@ { self = [super init]; if (!self) return self; - + interpreter = [source->interpreter retain]; honourhashbang = source->honourhashbang; debug = source->debug; @@ -81,36 +81,30 @@ with_terminal = source->with_terminal; prefskey = source->prefskey; if (prefskey) [prefskey retain]; - + return self; } - (id)initForFileType: (NSString *)filetype { FileSettings *defaults; - + defaults = [FileSettings getDefaultsForFileType: filetype]; self = [self initWithFileSettings: defaults]; origsource = [defaults retain]; return self; } -//- (id)init -//{ -// self = [self initForFileType: @"Python Script"]; -// return self; -//} - - (id)initForFSDefaultFileType: (NSString *)filetype { int i; NSString *filename; NSDictionary *dict; static NSDictionary *factorySettings; - + self = [super init]; if (!self) return self; - + if (factorySettings == NULL) { NSBundle *bdl = [NSBundle mainBundle]; NSString *path = [ bdl pathForResource: @"factorySettings" @@ -149,18 +143,18 @@ { NSUserDefaults *defaults; NSDictionary *dict; - + defaults = [NSUserDefaults standardUserDefaults]; dict = [defaults dictionaryForKey: filetype]; if (!dict) return; [self applyValuesFromDict: dict]; } - + - (id)initForDefaultFileType: (NSString *)filetype { FileSettings *fsdefaults; - + fsdefaults = [FileSettings getFactorySettingsForFileType: filetype]; self = [self initWithFileSettings: fsdefaults]; if (!self) return self; @@ -220,7 +214,7 @@ - (void)applyValuesFromDict: (NSDictionary *)dict { id value; - + value = [dict objectForKey: @"interpreter"]; if (value) interpreter = [value retain]; value = [dict objectForKey: @"honourhashbang"]; @@ -247,12 +241,12 @@ - (NSString*)_replaceSingleQuotes: (NSString*)string { - /* Replace all single-quotes by '"'"', that way shellquoting will - * be correct when the result value is delimited using single quotes. - */ - NSArray* components = [string componentsSeparatedByString:@"'"]; + /* Replace all single-quotes by '"'"', that way shellquoting will + * be correct when the result value is delimited using single quotes. + */ + NSArray* components = [string componentsSeparatedByString:@"'"]; - return [components componentsJoinedByString:@"'\"'\"'"]; + return [components componentsJoinedByString:@"'\"'\"'"]; } - (NSString *)commandLineForScript: (NSString *)script @@ -265,7 +259,7 @@ script_dir = [script substringToIndex: [script length]-[[script lastPathComponent] length]]; - + if (honourhashbang && (fp=fopen([script fileSystemRepresentation], "r")) && fgets(hashbangbuf, sizeof(hashbangbuf), fp) && @@ -278,7 +272,7 @@ } if (!cur_interp) cur_interp = interpreter; - + return [NSString stringWithFormat: @"cd '%@' && '%@'%s%s%s%s%s%s %@ '%@' %@ %s", [self _replaceSingleQuotes:script_dir], @@ -297,7 +291,7 @@ - (NSArray *) interpreters { return interpreters;}; -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return interpreter;}; - (BOOL) honourhashbang { return honourhashbang; }; - (BOOL) debug { return debug;}; diff --git a/Mac/PythonLauncher/MyAppDelegate.m b/Mac/PythonLauncher/MyAppDelegate.m --- a/Mac/PythonLauncher/MyAppDelegate.m +++ b/Mac/PythonLauncher/MyAppDelegate.m @@ -33,7 +33,7 @@ - (BOOL)shouldShowUI { - // if this call comes before applicationDidFinishLaunching: we + // if this call comes before applicationDidFinishLaunching: we // should terminate immedeately after starting the script. if (!initial_action_done) should_terminate = YES; @@ -62,7 +62,7 @@ static NSString *extensions[] = { @"py", @"pyw", @"pyc", NULL}; NSString **ext_p; int i; - + if ([[NSUserDefaults standardUserDefaults] boolForKey: @"SkipFileBindingTest"]) return; ourUrl = [NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]]; @@ -92,5 +92,5 @@ } } } - + @end diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m --- a/Mac/PythonLauncher/MyDocument.m +++ b/Mac/PythonLauncher/MyDocument.m @@ -16,7 +16,7 @@ { self = [super init]; if (self) { - + // Add your subclass-specific initialization here. // If an error occurs here, send a [self dealloc] message and return nil. script = [@".py" retain]; @@ -37,20 +37,17 @@ { NSApplication *app = [NSApplication sharedApplication]; [super close]; - if ([[app delegate] shouldTerminate]) + if ([(MyAppDelegate*)[app delegate] shouldTerminate]) [app terminate: self]; } - (void)load_defaults { -// if (settings) [settings release]; settings = [FileSettings newSettingsForFileType: filetype]; } - (void)update_display { -// [[self window] setTitle: script]; - [interpreter setStringValue: [settings interpreter]]; [honourhashbang setState: [settings honourhashbang]]; [debug setState: [settings debug]]; @@ -62,7 +59,7 @@ [others setStringValue: [settings others]]; [scriptargs setStringValue: [settings scriptargs]]; [with_terminal setState: [settings with_terminal]]; - + [commandline setStringValue: [settings commandLineForScript: script]]; } @@ -75,8 +72,8 @@ { const char *cmdline; int sts; - - cmdline = [[settings commandLineForScript: script] cString]; + + cmdline = [[settings commandLineForScript: script] UTF8String]; if ([settings with_terminal]) { sts = doscript(cmdline); } else { @@ -107,14 +104,13 @@ { // Insert code here to read your document from the given data. You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead. BOOL show_ui; - - // ask the app delegate whether we should show the UI or not. - show_ui = [[[NSApplication sharedApplication] delegate] shouldShowUI]; + + // ask the app delegate whether we should show the UI or not. + show_ui = [(MyAppDelegate*)[[NSApplication sharedApplication] delegate] shouldShowUI]; [script release]; script = [fileName retain]; [filetype release]; filetype = [type retain]; -// if (settings) [settings release]; settings = [FileSettings newSettingsForFileType: filetype]; if (show_ui) { [self update_display]; @@ -152,7 +148,7 @@ [self update_display]; } -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return [interpreter stringValue];}; - (BOOL) honourhashbang { return [honourhashbang state];}; - (BOOL) debug { return [debug state];}; diff --git a/Mac/PythonLauncher/PreferencesWindowController.m b/Mac/PythonLauncher/PreferencesWindowController.m --- a/Mac/PythonLauncher/PreferencesWindowController.m +++ b/Mac/PythonLauncher/PreferencesWindowController.m @@ -5,7 +5,7 @@ + getPreferencesWindow { static PreferencesWindowController *_singleton; - + if (!_singleton) _singleton = [[PreferencesWindowController alloc] init]; [_singleton showWindow: _singleton]; @@ -21,15 +21,13 @@ - (void)load_defaults { NSString *title = [filetype titleOfSelectedItem]; - + settings = [FileSettings getDefaultsForFileType: title]; } - (void)update_display { -// [[self window] setTitle: script]; - - [interpreter reloadData]; + [interpreter reloadData]; [interpreter setStringValue: [settings interpreter]]; [honourhashbang setState: [settings honourhashbang]]; [debug setState: [settings debug]]; @@ -41,7 +39,6 @@ [others setStringValue: [settings others]]; [with_terminal setState: [settings with_terminal]]; // Not scriptargs, it isn't for preferences - [commandline setStringValue: [settings commandLineForScript: @""]]; } @@ -75,7 +72,7 @@ [self update_display]; } -// FileSettingsSource protocol +// FileSettingsSource protocol - (NSString *) interpreter { return [interpreter stringValue];}; - (BOOL) honourhashbang { return [honourhashbang state]; }; - (BOOL) debug { return [debug state];}; @@ -98,23 +95,23 @@ // NSComboBoxDataSource protocol - (unsigned int)comboBox:(NSComboBox *)aComboBox indexOfItemWithStringValue:(NSString *)aString { - NSArray *interp_list = [settings interpreters]; + NSArray *interp_list = [settings interpreters]; unsigned int rv = [interp_list indexOfObjectIdenticalTo: aString]; - return rv; + return rv; } - (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)index { - NSArray *interp_list = [settings interpreters]; + NSArray *interp_list = [settings interpreters]; id rv = [interp_list objectAtIndex: index]; - return rv; + return rv; } - (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox { - NSArray *interp_list = [settings interpreters]; + NSArray *interp_list = [settings interpreters]; int rv = [interp_list count]; - return rv; + return rv; } diff --git a/Mac/PythonLauncher/doscript.h b/Mac/PythonLauncher/doscript.h --- a/Mac/PythonLauncher/doscript.h +++ b/Mac/PythonLauncher/doscript.h @@ -9,4 +9,4 @@ #include -extern int doscript(const char *command); \ No newline at end of file +extern int doscript(const char *command); diff --git a/Mac/PythonLauncher/doscript.m b/Mac/PythonLauncher/doscript.m --- a/Mac/PythonLauncher/doscript.m +++ b/Mac/PythonLauncher/doscript.m @@ -11,49 +11,49 @@ #import #import "doscript.h" -extern int +extern int doscript(const char *command) { - char *bundleID = "com.apple.Terminal"; - AppleEvent evt, res; - AEDesc desc; - OSStatus err; + char *bundleID = "com.apple.Terminal"; + AppleEvent evt, res; + AEDesc desc; + OSStatus err; - [[NSWorkspace sharedWorkspace] launchApplication:@"/Applications/Utilities/Terminal.app/"]; + [[NSWorkspace sharedWorkspace] launchApplication:@"/Applications/Utilities/Terminal.app/"]; - // Build event - err = AEBuildAppleEvent(kAECoreSuite, kAEDoScript, - typeApplicationBundleID, - bundleID, strlen(bundleID), - kAutoGenerateReturnID, - kAnyTransactionID, - &evt, NULL, - "'----':utf8(@)", strlen(command), - command); - if (err) { - NSLog(@"AEBuildAppleEvent failed: %d\n", err); - return err; - } + // Build event + err = AEBuildAppleEvent(kAECoreSuite, kAEDoScript, + typeApplicationBundleID, + bundleID, strlen(bundleID), + kAutoGenerateReturnID, + kAnyTransactionID, + &evt, NULL, + "'----':utf8(@)", strlen(command), + command); + if (err) { + NSLog(@"AEBuildAppleEvent failed: %ld\n", (long)err); + return err; + } - // Send event and check for any Apple Event Manager errors - err = AESendMessage(&evt, &res, kAEWaitReply, kAEDefaultTimeout); - AEDisposeDesc(&evt); - if (err) { - NSLog(@"AESendMessage failed: %d\n", err); - return err; - } - // Check for any application errors - err = AEGetParamDesc(&res, keyErrorNumber, typeSInt32, &desc); - AEDisposeDesc(&res); - if (!err) { - AEGetDescData(&desc, &err, sizeof(err)); - NSLog(@"Terminal returned an error: %d", err); - AEDisposeDesc(&desc); - } else if (err == errAEDescNotFound) { - err = noErr; - } else { - NSLog(@"AEGetPArmDesc returned an error: %d", err); - } + // Send event and check for any Apple Event Manager errors + err = AESendMessage(&evt, &res, kAEWaitReply, kAEDefaultTimeout); + AEDisposeDesc(&evt); + if (err) { + NSLog(@"AESendMessage failed: %ld\n", (long)err); + return err; + } + // Check for any application errors + err = AEGetParamDesc(&res, keyErrorNumber, typeSInt32, &desc); + AEDisposeDesc(&res); + if (!err) { + AEGetDescData(&desc, &err, sizeof(err)); + NSLog(@"Terminal returned an error: %ld", (long)err); + AEDisposeDesc(&desc); + } else if (err == errAEDescNotFound) { + err = noErr; + } else { + NSLog(@"AEGetPArmDesc returned an error: %ld", (long)err); + } - return err; + return err; } diff --git a/Mac/PythonLauncher/main.m b/Mac/PythonLauncher/main.m --- a/Mac/PythonLauncher/main.m +++ b/Mac/PythonLauncher/main.m @@ -11,7 +11,7 @@ int main(int argc, const char *argv[]) { - char *home = getenv("HOME"); - if (home) chdir(home); + char *home = getenv("HOME"); + if (home) chdir(home); return NSApplicationMain(argc, argv); } diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #18427: str.replace could crash the interpreter with huge strings. + - Issue #18347: ElementTree's html serializer now preserves the case of closing tags. @@ -67,6 +69,12 @@ - Issue #18113: Fixed a refcount leak in the curses.panel module's set_userptr() method. Reported by Atsuo Ishimoto. +Tools/Demos +----------- + +- Issue #12990: The "Python Launcher" on OSX could not launch python scripts + that have paths that include wide characters. + Build ----- @@ -82,7 +90,7 @@ - Issue #7136: In the Idle File menu, "New Window" is renamed "New File". Patch by Tal Einat, Roget Serwy, and Todd Rovito. - + - Issue #8515: Set __file__ when run file in IDLE. Initial patch by Bruce Frederiksen. diff --git a/Objects/stringobject.c b/Objects/stringobject.c --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -882,9 +882,9 @@ size -= chunk_size; } #ifdef __VMS - if (size) fwrite(data, (int)size, 1, fp); + if (size) fwrite(data, (size_t)size, 1, fp); #else - fwrite(data, 1, (int)size, fp); + fwrite(data, 1, (size_t)size, fp); #endif Py_END_ALLOW_THREADS return 0; @@ -2332,7 +2332,7 @@ } Py_LOCAL_INLINE(Py_ssize_t) -countchar(const char *target, int target_len, char c, Py_ssize_t maxcount) +countchar(const char *target, Py_ssize_t target_len, char c, Py_ssize_t maxcount) { Py_ssize_t count=0; const char *start=target; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2434,9 +2434,9 @@ PyDoc_STRVAR(sum_doc, "sum(sequence[, start]) -> value\n\ \n\ -Returns the sum of a sequence of numbers (NOT strings) plus the value\n\ +Return the sum of a sequence of numbers (NOT strings) plus the value\n\ of parameter 'start' (which defaults to 0). When the sequence is\n\ -empty, returns start."); +empty, return start."); static PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 18:21:55 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 18:21:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_reference_?= =?utf-8?q?leaks_introduced_by_the_patch_for_issue_=235308=2E?= Message-ID: <3brjFv1vxTz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/1cf2c42af815 changeset: 84545:1cf2c42af815 branch: 2.7 user: Serhiy Storchaka date: Thu Jul 11 19:14:07 2013 +0300 summary: Fix reference leaks introduced by the patch for issue #5308. files: Python/marshal.c | 20 +++++++++++--------- 1 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -88,7 +88,7 @@ } static void -w_string(char *s, Py_ssize_t n, WFILE *p) +w_string(const char *s, Py_ssize_t n, WFILE *p) { if (p->fp != NULL) { fwrite(s, 1, n, p->fp); @@ -141,6 +141,13 @@ # define W_SIZE w_long #endif +static void +w_pstring(const char *s, Py_ssize_t n, WFILE *p) +{ + W_SIZE(n, p); + w_string(s, n, p); +} + /* We assume that Python longs are stored internally in base some power of 2**15; for the sake of portability we'll always read and write them in base exactly 2**15. */ @@ -338,9 +345,7 @@ else { w_byte(TYPE_STRING, p); } - n = PyString_GET_SIZE(v); - W_SIZE(n, p); - w_string(PyString_AS_STRING(v), n, p); + w_pstring(PyBytes_AS_STRING(v), PyString_GET_SIZE(v), p); } #ifdef Py_USING_UNICODE else if (PyUnicode_CheckExact(v)) { @@ -352,9 +357,7 @@ return; } w_byte(TYPE_UNICODE, p); - n = PyString_GET_SIZE(utf8); - W_SIZE(n, p); - w_string(PyString_AS_STRING(utf8), n, p); + w_pstring(PyString_AS_STRING(utf8), PyString_GET_SIZE(utf8), p); Py_DECREF(utf8); } #endif @@ -441,8 +444,7 @@ PyBufferProcs *pb = v->ob_type->tp_as_buffer; w_byte(TYPE_STRING, p); n = (*pb->bf_getreadbuffer)(v, 0, (void **)&s); - W_SIZE(n, p); - w_string(s, n, p); + w_pstring(s, n, p); } else { w_byte(TYPE_UNKNOWN, p); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 18:21:56 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 18:21:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_reference_?= =?utf-8?q?leaks_introduced_by_the_patch_for_issue_=235308=2E?= Message-ID: <3brjFw4Clbz7Llb@mail.python.org> http://hg.python.org/cpython/rev/8b99f2224c3a changeset: 84546:8b99f2224c3a branch: 3.3 parent: 84542:8dd67c20cab7 user: Serhiy Storchaka date: Thu Jul 11 19:14:26 2013 +0300 summary: Fix reference leaks introduced by the patch for issue #5308. files: Python/marshal.c | 23 +++++++++++------------ 1 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -95,7 +95,7 @@ } static void -w_string(char *s, Py_ssize_t n, WFILE *p) +w_string(const char *s, Py_ssize_t n, WFILE *p) { if (p->fp != NULL) { fwrite(s, 1, n, p->fp); @@ -139,6 +139,13 @@ # define W_SIZE w_long #endif +static void +w_pstring(const char *s, Py_ssize_t n, WFILE *p) +{ + W_SIZE(n, p); + w_string(s, n, p); +} + /* We assume that Python longs are stored internally in base some power of 2**15; for the sake of portability we'll always read and write them in base exactly 2**15. */ @@ -313,9 +320,7 @@ } else if (PyBytes_CheckExact(v)) { w_byte(TYPE_STRING, p); - n = PyBytes_GET_SIZE(v); - W_SIZE(n, p); - w_string(PyBytes_AS_STRING(v), n, p); + w_pstring(PyBytes_AS_STRING(v), PyBytes_GET_SIZE(v), p); } else if (PyUnicode_CheckExact(v)) { PyObject *utf8; @@ -326,9 +331,7 @@ return; } w_byte(TYPE_UNICODE, p); - n = PyBytes_GET_SIZE(utf8); - W_SIZE(n, p); - w_string(PyBytes_AS_STRING(utf8), n, p); + w_pstring(PyBytes_AS_STRING(utf8), PyBytes_GET_SIZE(utf8), p); Py_DECREF(utf8); } else if (PyTuple_CheckExact(v)) { @@ -411,7 +414,6 @@ } else if (PyObject_CheckBuffer(v)) { /* Write unknown buffer-style objects as a string */ - char *s; Py_buffer view; if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) != 0) { w_byte(TYPE_UNKNOWN, p); @@ -420,10 +422,7 @@ return; } w_byte(TYPE_STRING, p); - n = view.len; - s = view.buf; - W_SIZE(n, p); - w_string(s, n, p); + w_pstring(view.buf, view.len, p); PyBuffer_Release(&view); } else { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 18:21:58 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 18:21:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_reference_leaks_introduced_by_the_patch_for_issue_?= =?utf-8?b?IzUzMDgu?= Message-ID: <3brjFy00Ysz7LlQ@mail.python.org> http://hg.python.org/cpython/rev/19ed630d8d75 changeset: 84547:19ed630d8d75 parent: 84543:a53ac166fa58 parent: 84546:8b99f2224c3a user: Serhiy Storchaka date: Thu Jul 11 19:19:47 2013 +0300 summary: Fix reference leaks introduced by the patch for issue #5308. files: Python/marshal.c | 23 +++++++++++------------ 1 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -97,7 +97,7 @@ } static void -w_string(char *s, Py_ssize_t n, WFILE *p) +w_string(const char *s, Py_ssize_t n, WFILE *p) { if (p->fp != NULL) { fwrite(s, 1, n, p->fp); @@ -141,6 +141,13 @@ # define W_SIZE w_long #endif +static void +w_pstring(const char *s, Py_ssize_t n, WFILE *p) +{ + W_SIZE(n, p); + w_string(s, n, p); +} + /* We assume that Python longs are stored internally in base some power of 2**15; for the sake of portability we'll always read and write them in base exactly 2**15. */ @@ -384,9 +391,7 @@ } else if (PyBytes_CheckExact(v)) { W_TYPE(TYPE_STRING, p); - n = PyBytes_GET_SIZE(v); - W_SIZE(n, p); - w_string(PyBytes_AS_STRING(v), n, p); + w_pstring(PyBytes_AS_STRING(v), PyBytes_GET_SIZE(v), p); } else if (PyUnicode_CheckExact(v)) { PyObject *utf8; @@ -400,9 +405,7 @@ W_TYPE(TYPE_INTERNED, p); else W_TYPE(TYPE_UNICODE, p); - n = PyBytes_GET_SIZE(utf8); - W_SIZE(n, p); - w_string(PyBytes_AS_STRING(utf8), n, p); + w_pstring(PyBytes_AS_STRING(utf8), PyBytes_GET_SIZE(utf8), p); Py_DECREF(utf8); } else if (PyTuple_CheckExact(v)) { @@ -485,7 +488,6 @@ } else if (PyObject_CheckBuffer(v)) { /* Write unknown buffer-style objects as a string */ - char *s; Py_buffer view; if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) != 0) { w_byte(TYPE_UNKNOWN, p); @@ -494,10 +496,7 @@ return; } W_TYPE(TYPE_STRING, p); - n = view.len; - s = view.buf; - W_SIZE(n, p); - w_string(s, n, p); + w_pstring(view.buf, view.len, p); PyBuffer_Release(&view); } else { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 18:30:10 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 11 Jul 2013 18:30:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3OTg3OiBwcm9w?= =?utf-8?q?erly_document_support=2Ecaptured=5Fxxx=2E?= Message-ID: <3brjRQ4qQpz7LkL@mail.python.org> http://hg.python.org/cpython/rev/af2416c2e27c changeset: 84548:af2416c2e27c branch: 3.3 parent: 84546:8b99f2224c3a user: R David Murray date: Thu Jul 11 12:28:40 2013 -0400 summary: #17987: properly document support.captured_xxx. Patch by Dmi Baranov. files: Doc/library/test.rst | 26 +++++++++++++++++++------- Lib/test/support.py | 19 +++++++++++++++++-- Lib/test/test_support.py | 17 ++++++++++------- Misc/ACKS | 1 + 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -362,17 +362,29 @@ New optional arguments *filters* and *quiet*. -.. function:: captured_stdout() +.. function:: captured_stdin() + captured_stdout() + captured_stderr() - A context manager that runs the :keyword:`with` statement body using a - :class:`io.StringIO` object as sys.stdout. That object can be retrieved - using the ``as`` clause of the :keyword:`with` statement. + A context managers that temporarily replaces the named stream with + :class:`io.StringIO` object. - Example use:: + Example use with output streams:: - with captured_stdout() as s: + with captured_stdout() as stdout, captured_stderr() as stderr: print("hello") - assert s.getvalue() == "hello\n" + print("error", file=sys.stderr) + assert stdout.getvalue() == "hello\n" + assert stderr.getvalue() == "error\n" + + Example use with input stream:: + + with captured_stdin() as stdin: + stdin.write('hello\n') + stdin.seek(0) + # call test code that consumes from sys.stdin + captured = input() + self.assertEqual(captured, "hello") .. function:: temp_cwd(name='tempcwd', quiet=False, path=None) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1184,16 +1184,31 @@ def captured_stdout(): """Capture the output of sys.stdout: - with captured_stdout() as s: + with captured_stdout() as stdout: print("hello") - self.assertEqual(s.getvalue(), "hello") + self.assertEqual(stdout.getvalue(), "hello\n") """ return captured_output("stdout") def captured_stderr(): + """Capture the output of sys.stderr: + + with captured_stderr() as stderr: + print("hello", file=sys.stderr) + self.assertEqual(stderr.getvalue(), "hello\n") + """ return captured_output("stderr") def captured_stdin(): + """Capture the input to sys.stdin: + + with captured_stdin() as stdin: + stdin.write('hello\n') + stdin.seek(0) + # call test code that consumes from sys.stdin + captured = input() + self.assertEqual(captured, "hello") + """ return captured_output("stdin") diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -130,19 +130,22 @@ self.assertNotIn("bar", sys.path) def test_captured_stdout(self): - with support.captured_stdout() as s: + with support.captured_stdout() as stdout: print("hello") - self.assertEqual(s.getvalue(), "hello\n") + self.assertEqual(stdout.getvalue(), "hello\n") def test_captured_stderr(self): - with support.captured_stderr() as s: + with support.captured_stderr() as stderr: print("hello", file=sys.stderr) - self.assertEqual(s.getvalue(), "hello\n") + self.assertEqual(stderr.getvalue(), "hello\n") def test_captured_stdin(self): - with support.captured_stdin() as s: - print("hello", file=sys.stdin) - self.assertEqual(s.getvalue(), "hello\n") + with support.captured_stdin() as stdin: + stdin.write('hello\n') + stdin.seek(0) + # call test code that consumes from sys.stdin + captured = input() + self.assertEqual(captured, "hello") def test_gc_collect(self): support.gc_collect() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -65,6 +65,7 @@ Jeff Balogh Manuel Balsera Matt Bandy +Dmi Baranov Michael J. Barber Daniel Barclay Nicolas Bareil -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 18:30:12 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 11 Jul 2013 18:30:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2317987=3A_properly_document_support=2Ecaptured?= =?utf-8?b?X3h4eC4=?= Message-ID: <3brjRS1Hccz7LlQ@mail.python.org> http://hg.python.org/cpython/rev/d0f7f1996001 changeset: 84549:d0f7f1996001 parent: 84547:19ed630d8d75 parent: 84548:af2416c2e27c user: R David Murray date: Thu Jul 11 12:29:31 2013 -0400 summary: Merge #17987: properly document support.captured_xxx. files: Doc/library/test.rst | 26 +++++++++++++++++++------- Lib/test/support.py | 19 +++++++++++++++++-- Lib/test/test_support.py | 17 ++++++++++------- Misc/ACKS | 1 + 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -362,17 +362,29 @@ New optional arguments *filters* and *quiet*. -.. function:: captured_stdout() +.. function:: captured_stdin() + captured_stdout() + captured_stderr() - A context manager that runs the :keyword:`with` statement body using a - :class:`io.StringIO` object as sys.stdout. That object can be retrieved - using the ``as`` clause of the :keyword:`with` statement. + A context managers that temporarily replaces the named stream with + :class:`io.StringIO` object. - Example use:: + Example use with output streams:: - with captured_stdout() as s: + with captured_stdout() as stdout, captured_stderr() as stderr: print("hello") - assert s.getvalue() == "hello\n" + print("error", file=sys.stderr) + assert stdout.getvalue() == "hello\n" + assert stderr.getvalue() == "error\n" + + Example use with input stream:: + + with captured_stdin() as stdin: + stdin.write('hello\n') + stdin.seek(0) + # call test code that consumes from sys.stdin + captured = input() + self.assertEqual(captured, "hello") .. function:: temp_cwd(name='tempcwd', quiet=False, path=None) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1186,16 +1186,31 @@ def captured_stdout(): """Capture the output of sys.stdout: - with captured_stdout() as s: + with captured_stdout() as stdout: print("hello") - self.assertEqual(s.getvalue(), "hello") + self.assertEqual(stdout.getvalue(), "hello\n") """ return captured_output("stdout") def captured_stderr(): + """Capture the output of sys.stderr: + + with captured_stderr() as stderr: + print("hello", file=sys.stderr) + self.assertEqual(stderr.getvalue(), "hello\n") + """ return captured_output("stderr") def captured_stdin(): + """Capture the input to sys.stdin: + + with captured_stdin() as stdin: + stdin.write('hello\n') + stdin.seek(0) + # call test code that consumes from sys.stdin + captured = input() + self.assertEqual(captured, "hello") + """ return captured_output("stdin") diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -130,19 +130,22 @@ self.assertNotIn("bar", sys.path) def test_captured_stdout(self): - with support.captured_stdout() as s: + with support.captured_stdout() as stdout: print("hello") - self.assertEqual(s.getvalue(), "hello\n") + self.assertEqual(stdout.getvalue(), "hello\n") def test_captured_stderr(self): - with support.captured_stderr() as s: + with support.captured_stderr() as stderr: print("hello", file=sys.stderr) - self.assertEqual(s.getvalue(), "hello\n") + self.assertEqual(stderr.getvalue(), "hello\n") def test_captured_stdin(self): - with support.captured_stdin() as s: - print("hello", file=sys.stdin) - self.assertEqual(s.getvalue(), "hello\n") + with support.captured_stdin() as stdin: + stdin.write('hello\n') + stdin.seek(0) + # call test code that consumes from sys.stdin + captured = input() + self.assertEqual(captured, "hello") def test_gc_collect(self): support.gc_collect() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -66,6 +66,7 @@ Jeff Balogh Manuel Balsera Matt Bandy +Dmi Baranov Michael J. Barber Daniel Barclay Nicolas Bareil -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 19:01:57 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 19:01:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318338=3A_=60pytho?= =?utf-8?q?n_--version=60_now_prints_version_string_to_stdout=2C_and?= Message-ID: <3brk854vr8z7LjQ@mail.python.org> http://hg.python.org/cpython/rev/e6384b8b2325 changeset: 84550:e6384b8b2325 user: Serhiy Storchaka date: Thu Jul 11 20:01:17 2013 +0300 summary: Issue #18338: `python --version` now prints version string to stdout, and not to stderr. Patch by Berker Peksag and Michael Dickens. files: Lib/test/test_cmd_line.py | 6 ++++-- Misc/NEWS | 3 +++ Modules/main.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -41,8 +41,10 @@ def test_version(self): version = ('Python %d.%d' % sys.version_info[:2]).encode("ascii") - rc, out, err = assert_python_ok('-V') - self.assertTrue(err.startswith(version)) + for switch in '-V', '--version': + rc, out, err = assert_python_ok(switch) + self.assertFalse(err.startswith(version)) + self.assertTrue(out.startswith(version)) def test_verbose(self): # -v causes imports to write to stderr. If the write to diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18338: `python --version` now prints version string to stdout, and + not to stderr. Patch by Berker Peksag and Michael Dickens. + - Issue #18426: Fix NULL pointer dereference in C extension import when PyModule_GetDef() returns an error. diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -500,7 +500,7 @@ return usage(0, argv[0]); if (version) { - fprintf(stderr, "Python %s\n", PY_VERSION); + printf("Python %s\n", PY_VERSION); return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 19:38:38 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 19:38:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MTAx?= =?utf-8?q?=3A_Tcl=2Esplit=28=29_now_process_Unicode_strings_nested_in_a_t?= =?utf-8?q?uple_as_it?= Message-ID: <3brkyQ3tQxzSwQ@mail.python.org> http://hg.python.org/cpython/rev/f53cdd4e2689 changeset: 84551:f53cdd4e2689 branch: 2.7 parent: 84545:1cf2c42af815 user: Serhiy Storchaka date: Thu Jul 11 20:32:48 2013 +0300 summary: Issue #18101: Tcl.split() now process Unicode strings nested in a tuple as it do with byte strings. Added tests for Tcl.split() and tcl.splitline(). files: Lib/test/test_tcl.py | 60 ++++++++++++++++++++++++++++++++ Misc/NEWS | 3 + Modules/_tkinter.c | 27 ++++++++++++++ 3 files changed, 90 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -184,6 +184,66 @@ self.assertEqual(passValue(f), f) self.assertEqual(passValue((1, '2', (3.4,))), (1, '2', (3.4,))) + def test_splitlist(self): + splitlist = self.interp.tk.splitlist + call = self.interp.tk.call + self.assertRaises(TypeError, splitlist) + self.assertRaises(TypeError, splitlist, 'a', 'b') + self.assertRaises(TypeError, splitlist, 2) + testcases = [ + ('2', ('2',)), + ('', ()), + ('{}', ('',)), + ('""', ('',)), + ('a\n b\t\r c\n ', ('a', 'b', 'c')), + (u'a\n b\t\r c\n ', ('a', 'b', 'c')), + ('a \xe2\x82\xac', ('a', '\xe2\x82\xac')), + (u'a \u20ac', ('a', '\xe2\x82\xac')), + ('a {b c}', ('a', 'b c')), + (r'a b\ c', ('a', 'b c')), + (('a', 'b c'), ('a', 'b c')), + ('a 2', ('a', '2')), + (('a', 2), ('a', 2)), + ('a 3.4', ('a', '3.4')), + (('a', 3.4), ('a', 3.4)), + ((), ()), + (call('list', 1, '2', (3.4,)), (1, '2', (3.4,))), + ] + for arg, res in testcases: + self.assertEqual(splitlist(arg), res) + self.assertRaises(TclError, splitlist, '{') + + def test_split(self): + split = self.interp.tk.split + call = self.interp.tk.call + self.assertRaises(TypeError, split) + self.assertRaises(TypeError, split, 'a', 'b') + self.assertRaises(TypeError, split, 2) + testcases = [ + ('2', '2'), + ('', ''), + ('{}', ''), + ('""', ''), + ('{', '{'), + ('a\n b\t\r c\n ', ('a', 'b', 'c')), + (u'a\n b\t\r c\n ', ('a', 'b', 'c')), + ('a \xe2\x82\xac', ('a', '\xe2\x82\xac')), + (u'a \u20ac', ('a', '\xe2\x82\xac')), + ('a {b c}', ('a', ('b', 'c'))), + (r'a b\ c', ('a', ('b', 'c'))), + (('a', 'b c'), ('a', ('b', 'c'))), + (('a', u'b c'), ('a', ('b', 'c'))), + ('a 2', ('a', '2')), + (('a', 2), ('a', 2)), + ('a 3.4', ('a', '3.4')), + (('a', 3.4), ('a', 3.4)), + (('a', (2, 3.4)), ('a', (2, 3.4))), + ((), ()), + (call('list', 1, '2', (3.4,)), (1, '2', (3.4,))), + ] + for arg, res in testcases: + self.assertEqual(split(arg), res) + def test_main(): test_support.run_unittest(TclTest, TkinterTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #18101: Tcl.split() now process Unicode strings nested in a tuple as it + do with byte strings. + - Issue #18427: str.replace could crash the interpreter with huge strings. - Issue #18347: ElementTree's html serializer now preserves the case of diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -547,6 +547,33 @@ return Split(PyString_AsString(arg)); /* Fall through, returning arg. */ } + else if (PyUnicode_Check(arg)) { + int argc; + char **argv; + char *list; + PyObject *s = PyUnicode_AsUTF8String(arg); + + if (s == NULL) { + Py_INCREF(arg); + return arg; + } + list = PyString_AsString(s); + + if (list == NULL || + Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { + Py_DECREF(s); + Py_INCREF(arg); + return arg; + } + Tcl_Free(FREECAST argv); + if (argc > 1) { + PyObject *v = Split(list); + Py_DECREF(s); + return v; + } + Py_DECREF(s); + /* Fall through, returning arg. */ + } Py_INCREF(arg); return arg; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 19:38:40 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 19:38:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MTAx?= =?utf-8?q?=3A_Tcl=2Esplit=28=29_now_process_strings_nested_in_a_tuple_as_?= =?utf-8?q?it?= Message-ID: <3brkyS0QW9zSyb@mail.python.org> http://hg.python.org/cpython/rev/9486c07929a1 changeset: 84552:9486c07929a1 branch: 3.3 parent: 84548:af2416c2e27c user: Serhiy Storchaka date: Thu Jul 11 20:34:47 2013 +0300 summary: Issue #18101: Tcl.split() now process strings nested in a tuple as it do with byte strings. Added tests for Tcl.split() and Tcl.splitline(). files: Lib/test/test_tcl.py | 60 ++++++++++++++++++++++++++++++++ Misc/NEWS | 3 + Modules/_tkinter.c | 15 ++++++++ 3 files changed, 78 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -175,6 +175,66 @@ self.assertEqual(passValue(f), f) self.assertEqual(passValue((1, '2', (3.4,))), (1, '2', (3.4,))) + def test_splitlist(self): + splitlist = self.interp.tk.splitlist + call = self.interp.tk.call + self.assertRaises(TypeError, splitlist) + self.assertRaises(TypeError, splitlist, 'a', 'b') + self.assertRaises(TypeError, splitlist, 2) + testcases = [ + ('2', ('2',)), + ('', ()), + ('{}', ('',)), + ('""', ('',)), + ('a\n b\t\r c\n ', ('a', 'b', 'c')), + (b'a\n b\t\r c\n ', ('a', 'b', 'c')), + ('a \u20ac', ('a', '\u20ac')), + (b'a \xe2\x82\xac', ('a', '\u20ac')), + ('a {b c}', ('a', 'b c')), + (r'a b\ c', ('a', 'b c')), + (('a', 'b c'), ('a', 'b c')), + ('a 2', ('a', '2')), + (('a', 2), ('a', 2)), + ('a 3.4', ('a', '3.4')), + (('a', 3.4), ('a', 3.4)), + ((), ()), + (call('list', 1, '2', (3.4,)), (1, '2', (3.4,))), + ] + for arg, res in testcases: + self.assertEqual(splitlist(arg), res, msg=arg) + self.assertRaises(TclError, splitlist, '{') + + def test_split(self): + split = self.interp.tk.split + call = self.interp.tk.call + self.assertRaises(TypeError, split) + self.assertRaises(TypeError, split, 'a', 'b') + self.assertRaises(TypeError, split, 2) + testcases = [ + ('2', '2'), + ('', ''), + ('{}', ''), + ('""', ''), + ('{', '{'), + ('a\n b\t\r c\n ', ('a', 'b', 'c')), + (b'a\n b\t\r c\n ', ('a', 'b', 'c')), + ('a \u20ac', ('a', '\u20ac')), + (b'a \xe2\x82\xac', ('a', '\u20ac')), + ('a {b c}', ('a', ('b', 'c'))), + (r'a b\ c', ('a', ('b', 'c'))), + (('a', b'b c'), ('a', ('b', 'c'))), + (('a', 'b c'), ('a', ('b', 'c'))), + ('a 2', ('a', '2')), + (('a', 2), ('a', 2)), + ('a 3.4', ('a', '3.4')), + (('a', 3.4), ('a', 3.4)), + (('a', (2, 3.4)), ('a', (2, 3.4))), + ((), ()), + (call('list', 1, '2', (3.4,)), (1, '2', (3.4,))), + ] + for arg, res in testcases: + self.assertEqual(split(arg), res, msg=arg) + def test_main(): support.run_unittest(TclTest, TkinterTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,9 @@ Library ------- +- Issue #18101: Tcl.split() now process strings nested in a tuple as it + do with byte strings. + - Issue #17198: Fix a NameError in the dbm module. Patch by Valentina Mukhamedzhanova. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -519,6 +519,21 @@ return result; /* Fall through, returning arg. */ } + else if (PyUnicode_Check(arg)) { + int argc; + char **argv; + char *list = PyUnicode_AsUTF8(arg); + + if (list == NULL || + Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { + Py_INCREF(arg); + return arg; + } + Tcl_Free(FREECAST argv); + if (argc > 1) + return Split(list); + /* Fall through, returning arg. */ + } else if (PyBytes_Check(arg)) { int argc; char **argv; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 19:38:41 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 19:38:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318101=3A_Tcl=2Esplit=28=29_now_process_strings_?= =?utf-8?q?nested_in_a_tuple_as_it?= Message-ID: <3brkyT3xzcz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/16c48d553ddb changeset: 84553:16c48d553ddb parent: 84550:e6384b8b2325 parent: 84552:9486c07929a1 user: Serhiy Storchaka date: Thu Jul 11 20:36:00 2013 +0300 summary: Issue #18101: Tcl.split() now process strings nested in a tuple as it do with byte strings. Added tests for Tcl.split() and Tcl.splitline(). files: Lib/test/test_tcl.py | 60 ++++++++++++++++++++++++++++++++ Misc/NEWS | 3 + Modules/_tkinter.c | 15 ++++++++ 3 files changed, 78 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -175,6 +175,66 @@ self.assertEqual(passValue(f), f) self.assertEqual(passValue((1, '2', (3.4,))), (1, '2', (3.4,))) + def test_splitlist(self): + splitlist = self.interp.tk.splitlist + call = self.interp.tk.call + self.assertRaises(TypeError, splitlist) + self.assertRaises(TypeError, splitlist, 'a', 'b') + self.assertRaises(TypeError, splitlist, 2) + testcases = [ + ('2', ('2',)), + ('', ()), + ('{}', ('',)), + ('""', ('',)), + ('a\n b\t\r c\n ', ('a', 'b', 'c')), + (b'a\n b\t\r c\n ', ('a', 'b', 'c')), + ('a \u20ac', ('a', '\u20ac')), + (b'a \xe2\x82\xac', ('a', '\u20ac')), + ('a {b c}', ('a', 'b c')), + (r'a b\ c', ('a', 'b c')), + (('a', 'b c'), ('a', 'b c')), + ('a 2', ('a', '2')), + (('a', 2), ('a', 2)), + ('a 3.4', ('a', '3.4')), + (('a', 3.4), ('a', 3.4)), + ((), ()), + (call('list', 1, '2', (3.4,)), (1, '2', (3.4,))), + ] + for arg, res in testcases: + self.assertEqual(splitlist(arg), res, msg=arg) + self.assertRaises(TclError, splitlist, '{') + + def test_split(self): + split = self.interp.tk.split + call = self.interp.tk.call + self.assertRaises(TypeError, split) + self.assertRaises(TypeError, split, 'a', 'b') + self.assertRaises(TypeError, split, 2) + testcases = [ + ('2', '2'), + ('', ''), + ('{}', ''), + ('""', ''), + ('{', '{'), + ('a\n b\t\r c\n ', ('a', 'b', 'c')), + (b'a\n b\t\r c\n ', ('a', 'b', 'c')), + ('a \u20ac', ('a', '\u20ac')), + (b'a \xe2\x82\xac', ('a', '\u20ac')), + ('a {b c}', ('a', ('b', 'c'))), + (r'a b\ c', ('a', ('b', 'c'))), + (('a', b'b c'), ('a', ('b', 'c'))), + (('a', 'b c'), ('a', ('b', 'c'))), + ('a 2', ('a', '2')), + (('a', 2), ('a', 2)), + ('a 3.4', ('a', '3.4')), + (('a', 3.4), ('a', 3.4)), + (('a', (2, 3.4)), ('a', (2, 3.4))), + ((), ()), + (call('list', 1, '2', (3.4,)), (1, '2', (3.4,))), + ] + for arg, res in testcases: + self.assertEqual(split(arg), res, msg=arg) + def test_main(): support.run_unittest(TclTest, TkinterTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -148,6 +148,9 @@ Library ------- +- Issue #18101: Tcl.split() now process strings nested in a tuple as it + do with byte strings. + - Issue #18116: getpass was always getting an error when testing /dev/tty, and thus was always falling back to stdin. It also leaked an open file when it did so. Both of these issues are now fixed. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -423,6 +423,21 @@ return result; /* Fall through, returning arg. */ } + else if (PyUnicode_Check(arg)) { + int argc; + char **argv; + char *list = PyUnicode_AsUTF8(arg); + + if (list == NULL || + Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { + Py_INCREF(arg); + return arg; + } + Tcl_Free(FREECAST argv); + if (argc > 1) + return Split(list); + /* Fall through, returning arg. */ + } else if (PyBytes_Check(arg)) { int argc; char **argv; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 21:01:31 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 21:01:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDg1?= =?utf-8?q?=3A_Add_missed_const_modifier_for_some_entries_in_refcounts=2Ed?= =?utf-8?b?YXQu?= Message-ID: <3brmp33kCzzSDD@mail.python.org> http://hg.python.org/cpython/rev/ffe24e3e7a2a changeset: 84554:ffe24e3e7a2a branch: 3.3 parent: 84552:9486c07929a1 user: Serhiy Storchaka date: Thu Jul 11 21:57:34 2013 +0300 summary: Issue #18085: Add missed const modifier for some entries in refcounts.dat. files: Doc/data/refcounts.dat | 154 ++++++++++++++-------------- 1 files changed, 77 insertions(+), 77 deletions(-) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -210,7 +210,7 @@ PyDict_DelItemString:int::: PyDict_DelItemString:PyObject*:p:0: -PyDict_DelItemString:char*:key:: +PyDict_DelItemString:const char*:key:: PyDict_GetItem:PyObject*::0:0 PyDict_GetItem:PyObject*:p:0: @@ -218,7 +218,7 @@ PyDict_GetItemString:PyObject*::0: PyDict_GetItemString:PyObject*:p:0: -PyDict_GetItemString:char*:key:: +PyDict_GetItemString:const char*:key:: PyDict_Items:PyObject*::+1: PyDict_Items:PyObject*:p:0: @@ -244,7 +244,7 @@ PyDict_SetItemString:int::: PyDict_SetItemString:PyObject*:p:0: -PyDict_SetItemString:char*:key:: +PyDict_SetItemString:const char*:key:: PyDict_SetItemString:PyObject*:val:+1: PyDict_Size:int::: @@ -277,13 +277,13 @@ PyErr_GivenExceptionMatches:PyObject*:exc:0: PyErr_NewException:PyObject*::+1: -PyErr_NewException:char*:name:: +PyErr_NewException:const char*:name:: PyErr_NewException:PyObject*:base:0: PyErr_NewException:PyObject*:dict:0: PyErr_NewExceptionWithDoc:PyObject*::+1: -PyErr_NewExceptionWithDoc:char*:name:: -PyErr_NewExceptionWithDoc:char*:doc:: +PyErr_NewExceptionWithDoc:const char*:name:: +PyErr_NewExceptionWithDoc:const char*:doc:: PyErr_NewExceptionWithDoc:PyObject*:base:0: PyErr_NewExceptionWithDoc:PyObject*:dict:0: @@ -310,21 +310,21 @@ PyErr_SetExcFromWindowsErrWithFilename:PyObject*::null: PyErr_SetExcFromWindowsErrWithFilename:PyObject*:type:0: PyErr_SetExcFromWindowsErrWithFilename:int:ierr:: -PyErr_SetExcFromWindowsErrWithFilename:char*:filename:: +PyErr_SetExcFromWindowsErrWithFilename:const char*:filename:: PyErr_SetFromErrno:PyObject*::null: PyErr_SetFromErrno:PyObject*:type:0: PyErr_SetFromErrnoWithFilename:PyObject*::null: PyErr_SetFromErrnoWithFilename:PyObject*:type:0: -PyErr_SetFromErrnoWithFilename:char*:filename:: +PyErr_SetFromErrnoWithFilename:const char*:filename:: PyErr_SetFromWindowsErr:PyObject*::null: PyErr_SetFromWindowsErr:int:ierr:: PyErr_SetFromWindowsErrWithFilename:PyObject*::null: PyErr_SetFromWindowsErrWithFilename:int:ierr:: -PyErr_SetFromWindowsErrWithFilename:char*:filename:: +PyErr_SetFromWindowsErrWithFilename:const char*:filename:: PyErr_SetInterrupt:void::: @@ -337,11 +337,11 @@ PyErr_SetString:void::: PyErr_SetString:PyObject*:type:+1: -PyErr_SetString:char*:message:: +PyErr_SetString:const char*:message:: PyErr_Format:PyObject*::null: PyErr_Format:PyObject*:exception:+1: -PyErr_Format:char*:format:: +PyErr_Format:const char*:format:: PyErr_Format::...:: PyErr_WarnEx:int::: @@ -386,22 +386,22 @@ PyFile_FromFile:PyObject*::+1: PyFile_FromFile:FILE*:fp:: -PyFile_FromFile:char*:name:: -PyFile_FromFile:char*:mode:: +PyFile_FromFile:const char*:name:: +PyFile_FromFile:const char*:mode:: PyFile_FromFile:int(*:close):: PyFile_FromFileEx:PyObject*::+1: PyFile_FromFileEx:FILE*:fp:: -PyFile_FromFileEx:char*:name:: -PyFile_FromFileEx:char*:mode:: +PyFile_FromFileEx:const char*:name:: +PyFile_FromFileEx:const char*:mode:: PyFile_FromFileEx:int(*:close):: PyFile_FromFileEx:int:buffering:: -PyFile_FromFileEx:char*:encoding:: -PyFile_FromFileEx:char*:newline:: +PyFile_FromFileEx:const char*:encoding:: +PyFile_FromFileEx:const char*:newline:: PyFile_FromString:PyObject*::+1: -PyFile_FromString:char*:name:: -PyFile_FromString:char*:mode:: +PyFile_FromString:const char*:name:: +PyFile_FromString:const char*:mode:: PyFile_GetLine:PyObject*::+1: PyFile_GetLine:PyObject*:p:: @@ -482,23 +482,23 @@ PyGen_New:PyFrameObject*:frame:0: Py_InitModule:PyObject*::0: -Py_InitModule:char*:name:: +Py_InitModule:const char*:name:: Py_InitModule:PyMethodDef[]:methods:: Py_InitModule3:PyObject*::0: -Py_InitModule3:char*:name:: +Py_InitModule3:const char*:name:: Py_InitModule3:PyMethodDef[]:methods:: -Py_InitModule3:char*:doc:: +Py_InitModule3:const char*:doc:: Py_InitModule4:PyObject*::0: -Py_InitModule4:char*:name:: +Py_InitModule4:const char*:name:: Py_InitModule4:PyMethodDef[]:methods:: -Py_InitModule4:char*:doc:: +Py_InitModule4:const char*:doc:: Py_InitModule4:PyObject*:self:: Py_InitModule4:int:apiver::usually provided by Py_InitModule or Py_InitModule3 PyImport_AddModule:PyObject*::0:reference borrowed from sys.modules -PyImport_AddModule:char*:name:: +PyImport_AddModule:const char*:name:: PyImport_Cleanup:void::: @@ -522,16 +522,16 @@ PyImport_ImportFrozenModule:char*::: PyImport_ImportModule:PyObject*::+1: -PyImport_ImportModule:char*:name:: +PyImport_ImportModule:const char*:name:: PyImport_ImportModuleEx:PyObject*::+1: -PyImport_ImportModuleEx:char*:name:: +PyImport_ImportModuleEx:const char*:name:: PyImport_ImportModuleEx:PyObject*:globals:0:??? PyImport_ImportModuleEx:PyObject*:locals:0:??? PyImport_ImportModuleEx:PyObject*:fromlist:0:??? PyImport_ImportModuleLevel:PyObject*::+1: -PyImport_ImportModuleLevel:char*:name:: +PyImport_ImportModuleLevel:const char*:name:: PyImport_ImportModuleLevel:PyObject*:globals:0:??? PyImport_ImportModuleLevel:PyObject*:locals:0:??? PyImport_ImportModuleLevel:PyObject*:fromlist:0:??? @@ -692,7 +692,7 @@ PyMapping_DelItemString:int::: PyMapping_DelItemString:PyObject*:o:0: -PyMapping_DelItemString:char*:key:: +PyMapping_DelItemString:const char*:key:: PyMapping_GetItemString:PyObject*::+1: PyMapping_GetItemString:PyObject*:o:0: @@ -762,10 +762,10 @@ PyModule_GetDict:PyObject*::0: PyModule_GetDict::PyObject* module:0: -PyModule_GetFilename:char*::: +PyModule_GetFilename:const char*::: PyModule_GetFilename:PyObject*:module:0: -PyModule_GetName:char*::: +PyModule_GetName:const char*::: PyModule_GetName:PyObject*:module:0: PyModule_New:PyObject*::+1: @@ -949,7 +949,7 @@ PyObject_DelAttrString:int::: PyObject_DelAttrString:PyObject*:o:0: -PyObject_DelAttrString:char*:attr_name:: +PyObject_DelAttrString:const char*:attr_name:: PyObject_DelItem:int::: PyObject_DelItem:PyObject*:o:0: @@ -964,7 +964,7 @@ PyObject_GetAttrString:PyObject*::+1: PyObject_GetAttrString:PyObject*:o:0: -PyObject_GetAttrString:char*:attr_name:: +PyObject_GetAttrString:const char*:attr_name:: PyObject_GetItem:PyObject*::+1: PyObject_GetItem:PyObject*:o:0: @@ -979,7 +979,7 @@ PyObject_HasAttrString:int::: PyObject_HasAttrString:PyObject*:o:0: -PyObject_HasAttrString:char*:attr_name:0: +PyObject_HasAttrString:const char*:attr_name:0: PyObject_Hash:int::: PyObject_Hash:PyObject*:o:0: @@ -1029,7 +1029,7 @@ PyObject_SetAttrString:int::: PyObject_SetAttrString:PyObject*:o:0: -PyObject_SetAttrString:char*:attr_name:: +PyObject_SetAttrString:const char*:attr_name:: PyObject_SetAttrString:PyObject*:v:+1: PyObject_SetItem:int::: @@ -1048,27 +1048,27 @@ PyParser_SimpleParseFile:struct _node*::: PyParser_SimpleParseFile:FILE*:fp:: -PyParser_SimpleParseFile:char*:filename:: +PyParser_SimpleParseFile:const char*:filename:: PyParser_SimpleParseFile:int:start:: PyParser_SimpleParseString:struct _node*::: -PyParser_SimpleParseString:char*:str:: +PyParser_SimpleParseString:const char*:str:: PyParser_SimpleParseString:int:start:: PyRun_AnyFile:int::: PyRun_AnyFile:FILE*:fp:: -PyRun_AnyFile:char*:filename:: +PyRun_AnyFile:const char*:filename:: PyRun_File:PyObject*::+1:??? -- same as eval_code2() PyRun_File:FILE*:fp:: -PyRun_File:char*:filename:: +PyRun_File:const char*:filename:: PyRun_File:int:start:: PyRun_File:PyObject*:globals:0: PyRun_File:PyObject*:locals:0: PyRun_FileEx:PyObject*::+1:??? -- same as eval_code2() PyRun_FileEx:FILE*:fp:: -PyRun_FileEx:char*:filename:: +PyRun_FileEx:const char*:filename:: PyRun_FileEx:int:start:: PyRun_FileEx:PyObject*:globals:0: PyRun_FileEx:PyObject*:locals:0: @@ -1076,7 +1076,7 @@ PyRun_FileFlags:PyObject*::+1:??? -- same as eval_code2() PyRun_FileFlags:FILE*:fp:: -PyRun_FileFlags:char*:filename:: +PyRun_FileFlags:const char*:filename:: PyRun_FileFlags:int:start:: PyRun_FileFlags:PyObject*:globals:0: PyRun_FileFlags:PyObject*:locals:0: @@ -1084,7 +1084,7 @@ PyRun_FileExFlags:PyObject*::+1:??? -- same as eval_code2() PyRun_FileExFlags:FILE*:fp:: -PyRun_FileExFlags:char*:filename:: +PyRun_FileExFlags:const char*:filename:: PyRun_FileExFlags:int:start:: PyRun_FileExFlags:PyObject*:globals:0: PyRun_FileExFlags:PyObject*:locals:0: @@ -1093,27 +1093,27 @@ PyRun_InteractiveLoop:int::: PyRun_InteractiveLoop:FILE*:fp:: -PyRun_InteractiveLoop:char*:filename:: +PyRun_InteractiveLoop:const char*:filename:: PyRun_InteractiveOne:int::: PyRun_InteractiveOne:FILE*:fp:: -PyRun_InteractiveOne:char*:filename:: +PyRun_InteractiveOne:const char*:filename:: PyRun_SimpleFile:int::: PyRun_SimpleFile:FILE*:fp:: -PyRun_SimpleFile:char*:filename:: +PyRun_SimpleFile:const char*:filename:: PyRun_SimpleString:int::: -PyRun_SimpleString:char*:command:: +PyRun_SimpleString:const char*:command:: PyRun_String:PyObject*::+1:??? -- same as eval_code2() -PyRun_String:char*:str:: +PyRun_String:const char*:str:: PyRun_String:int:start:: PyRun_String:PyObject*:globals:0: PyRun_String:PyObject*:locals:0: PyRun_StringFlags:PyObject*::+1:??? -- same as eval_code2() -PyRun_StringFlags:char*:str:: +PyRun_StringFlags:const char*:str:: PyRun_StringFlags:int:start:: PyRun_StringFlags:PyObject*:globals:0: PyRun_StringFlags:PyObject*:locals:0: @@ -1229,7 +1229,7 @@ PySlice_New:PyObject*:stop:0: PySlice_New:PyObject*:step:0: -PyString_AS_STRING:char*::: +PyString_AS_STRING:const char*::: PyString_AS_STRING:PyObject*:string:0: PyString_AsDecodedObject:PyObject*::+1: @@ -1242,7 +1242,7 @@ PyString_AsEncodedObject:const char*:encoding:: PyString_AsEncodedObject:const char*:errors:: -PyString_AsString:char*::: +PyString_AsString:const char*::: PyString_AsString:PyObject*:string:0: PyString_AsStringAndSize:int::: @@ -1310,13 +1310,13 @@ PyString_AsEncodedString:const char*:errors:: PySys_AddWarnOption:void::: -PySys_AddWarnOption:char*:s:: +PySys_AddWarnOption:const char*:s:: PySys_AddXOption:void::: PySys_AddXOption:const wchar_t*:s:: PySys_GetObject:PyObject*::0: -PySys_GetObject:char*:name:: +PySys_GetObject:const char*:name:: PySys_GetXOptions:PyObject*::0: @@ -1325,16 +1325,16 @@ PySys_SetArgv:char**:argv:: PySys_SetObject:int::: -PySys_SetObject:char*:name:: +PySys_SetObject:const char*:name:: PySys_SetObject:PyObject*:v:+1: PySys_ResetWarnOptions:void::: PySys_WriteStdout:void::: -PySys_WriteStdout:char*:format:: +PySys_WriteStdout:const char*:format:: PySys_WriteStderr:void::: -PySys_WriteStderr:char*:format:: +PySys_WriteStderr:const char*:format:: PyThreadState_Clear:void::: PyThreadState_Clear:PyThreadState*:tstate:: @@ -1714,16 +1714,16 @@ Py_AtExit:void (*)():func:: Py_BuildValue:PyObject*::+1: -Py_BuildValue:char*:format:: +Py_BuildValue:const char*:format:: Py_CompileString:PyObject*::+1: -Py_CompileString:char*:str:: -Py_CompileString:char*:filename:: +Py_CompileString:const char*:str:: +Py_CompileString:const char*:filename:: Py_CompileString:int:start:: Py_CompileStringFlags:PyObject*::+1: -Py_CompileStringFlags:char*:str:: -Py_CompileStringFlags:char*:filename:: +Py_CompileStringFlags:const char*:str:: +Py_CompileStringFlags:const char*:filename:: Py_CompileStringFlags:int:start:: Py_CompileStringFlags:PyCompilerFlags*:flags:: @@ -1737,33 +1737,33 @@ Py_Exit:int:status:: Py_FatalError:void::: -Py_FatalError:char*:message:: +Py_FatalError:const char*:message:: Py_FdIsInteractive:int::: Py_FdIsInteractive:FILE*:fp:: -Py_FdIsInteractive:char*:filename:: +Py_FdIsInteractive:const char*:filename:: Py_Finalize:void::: -Py_GetBuildInfoconst:char*::: +Py_GetBuildInfoconst:const char*::: -Py_GetCompilerconst:char*::: +Py_GetCompilerconst:const char*::: -Py_GetCopyrightconst:char*::: +Py_GetCopyrightconst:const char*::: -Py_GetExecPrefix:char*::: +Py_GetExecPrefix:const char*::: -Py_GetPath:char*::: +Py_GetPath:const char*::: -Py_GetPlatformconst:char*::: +Py_GetPlatformconst:const char*::: -Py_GetPrefix:char*::: +Py_GetPrefix:const char*::: -Py_GetProgramFullPath:char*::: +Py_GetProgramFullPath:const char*::: -Py_GetProgramName:char*::: +Py_GetProgramName:const char*::: -Py_GetVersionconst:char*::: +Py_GetVersionconst:const char*::: Py_INCREF:void::: Py_INCREF:PyObject*:o:+1: @@ -1775,7 +1775,7 @@ Py_NewInterpreter:PyThreadState*::: Py_SetProgramName:void::: -Py_SetProgramName:char*:name:: +Py_SetProgramName:const char*:name:: Py_XDECREF:void::: Py_XDECREF:PyObject*:o:-1:if o is not NULL @@ -1784,14 +1784,14 @@ Py_XINCREF:PyObject*:o:+1:if o is not NULL _PyImport_FindExtension:PyObject*::0:??? see PyImport_AddModule -_PyImport_FindExtension:char*::: -_PyImport_FindExtension:char*::: +_PyImport_FindExtension:const char*::: +_PyImport_FindExtension:const char*::: _PyImport_Fini:void::: _PyImport_FixupExtension:PyObject*:::??? -_PyImport_FixupExtension:char*::: -_PyImport_FixupExtension:char*::: +_PyImport_FixupExtension:const char*::: +_PyImport_FixupExtension:const char*::: _PyImport_Init:void::: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 21:01:33 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 21:01:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318085=3A_Add_missed_const_modifier_for_some_ent?= =?utf-8?q?ries_in_refcounts=2Edat=2E?= Message-ID: <3brmp503ZFzSxC@mail.python.org> http://hg.python.org/cpython/rev/6587fd3d89ae changeset: 84555:6587fd3d89ae parent: 84553:16c48d553ddb parent: 84554:ffe24e3e7a2a user: Serhiy Storchaka date: Thu Jul 11 22:00:57 2013 +0300 summary: Issue #18085: Add missed const modifier for some entries in refcounts.dat. files: Doc/data/refcounts.dat | 152 ++++++++++++++-------------- 1 files changed, 76 insertions(+), 76 deletions(-) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -210,7 +210,7 @@ PyDict_DelItemString:int::: PyDict_DelItemString:PyObject*:p:0: -PyDict_DelItemString:char*:key:: +PyDict_DelItemString:const char*:key:: PyDict_GetItem:PyObject*::0:0 PyDict_GetItem:PyObject*:p:0: @@ -249,7 +249,7 @@ PyDict_SetItemString:int::: PyDict_SetItemString:PyObject*:p:0: -PyDict_SetItemString:char*:key:: +PyDict_SetItemString:const char*:key:: PyDict_SetItemString:PyObject*:val:+1: PyDict_Size:int::: @@ -282,13 +282,13 @@ PyErr_GivenExceptionMatches:PyObject*:exc:0: PyErr_NewException:PyObject*::+1: -PyErr_NewException:char*:name:: +PyErr_NewException:const char*:name:: PyErr_NewException:PyObject*:base:0: PyErr_NewException:PyObject*:dict:0: PyErr_NewExceptionWithDoc:PyObject*::+1: -PyErr_NewExceptionWithDoc:char*:name:: -PyErr_NewExceptionWithDoc:char*:doc:: +PyErr_NewExceptionWithDoc:const char*:name:: +PyErr_NewExceptionWithDoc:const char*:doc:: PyErr_NewExceptionWithDoc:PyObject*:base:0: PyErr_NewExceptionWithDoc:PyObject*:dict:0: @@ -315,21 +315,21 @@ PyErr_SetExcFromWindowsErrWithFilename:PyObject*::null: PyErr_SetExcFromWindowsErrWithFilename:PyObject*:type:0: PyErr_SetExcFromWindowsErrWithFilename:int:ierr:: -PyErr_SetExcFromWindowsErrWithFilename:char*:filename:: +PyErr_SetExcFromWindowsErrWithFilename:const char*:filename:: PyErr_SetFromErrno:PyObject*::null: PyErr_SetFromErrno:PyObject*:type:0: PyErr_SetFromErrnoWithFilename:PyObject*::null: PyErr_SetFromErrnoWithFilename:PyObject*:type:0: -PyErr_SetFromErrnoWithFilename:char*:filename:: +PyErr_SetFromErrnoWithFilename:const char*:filename:: PyErr_SetFromWindowsErr:PyObject*::null: PyErr_SetFromWindowsErr:int:ierr:: PyErr_SetFromWindowsErrWithFilename:PyObject*::null: PyErr_SetFromWindowsErrWithFilename:int:ierr:: -PyErr_SetFromWindowsErrWithFilename:char*:filename:: +PyErr_SetFromWindowsErrWithFilename:const char*:filename:: PyErr_SetInterrupt:void::: @@ -342,11 +342,11 @@ PyErr_SetString:void::: PyErr_SetString:PyObject*:type:+1: -PyErr_SetString:char*:message:: +PyErr_SetString:const char*:message:: PyErr_Format:PyObject*::null: PyErr_Format:PyObject*:exception:+1: -PyErr_Format:char*:format:: +PyErr_Format:const char*:format:: PyErr_Format::...:: PyErr_WarnEx:int::: @@ -391,22 +391,22 @@ PyFile_FromFile:PyObject*::+1: PyFile_FromFile:FILE*:fp:: -PyFile_FromFile:char*:name:: -PyFile_FromFile:char*:mode:: +PyFile_FromFile:const char*:name:: +PyFile_FromFile:const char*:mode:: PyFile_FromFile:int(*:close):: PyFile_FromFileEx:PyObject*::+1: PyFile_FromFileEx:FILE*:fp:: -PyFile_FromFileEx:char*:name:: -PyFile_FromFileEx:char*:mode:: +PyFile_FromFileEx:const char*:name:: +PyFile_FromFileEx:const char*:mode:: PyFile_FromFileEx:int(*:close):: PyFile_FromFileEx:int:buffering:: -PyFile_FromFileEx:char*:encoding:: -PyFile_FromFileEx:char*:newline:: +PyFile_FromFileEx:const char*:encoding:: +PyFile_FromFileEx:const char*:newline:: PyFile_FromString:PyObject*::+1: -PyFile_FromString:char*:name:: -PyFile_FromString:char*:mode:: +PyFile_FromString:const char*:name:: +PyFile_FromString:const char*:mode:: PyFile_GetLine:PyObject*::+1: PyFile_GetLine:PyObject*:p:: @@ -487,23 +487,23 @@ PyGen_New:PyFrameObject*:frame:0: Py_InitModule:PyObject*::0: -Py_InitModule:char*:name:: +Py_InitModule:const char*:name:: Py_InitModule:PyMethodDef[]:methods:: Py_InitModule3:PyObject*::0: -Py_InitModule3:char*:name:: +Py_InitModule3:const char*:name:: Py_InitModule3:PyMethodDef[]:methods:: -Py_InitModule3:char*:doc:: +Py_InitModule3:const char*:doc:: Py_InitModule4:PyObject*::0: -Py_InitModule4:char*:name:: +Py_InitModule4:const char*:name:: Py_InitModule4:PyMethodDef[]:methods:: -Py_InitModule4:char*:doc:: +Py_InitModule4:const char*:doc:: Py_InitModule4:PyObject*:self:: Py_InitModule4:int:apiver::usually provided by Py_InitModule or Py_InitModule3 PyImport_AddModule:PyObject*::0:reference borrowed from sys.modules -PyImport_AddModule:char*:name:: +PyImport_AddModule:const char*:name:: PyImport_Cleanup:void::: @@ -527,16 +527,16 @@ PyImport_ImportFrozenModule:char*::: PyImport_ImportModule:PyObject*::+1: -PyImport_ImportModule:char*:name:: +PyImport_ImportModule:const char*:name:: PyImport_ImportModuleEx:PyObject*::+1: -PyImport_ImportModuleEx:char*:name:: +PyImport_ImportModuleEx:const char*:name:: PyImport_ImportModuleEx:PyObject*:globals:0:??? PyImport_ImportModuleEx:PyObject*:locals:0:??? PyImport_ImportModuleEx:PyObject*:fromlist:0:??? PyImport_ImportModuleLevel:PyObject*::+1: -PyImport_ImportModuleLevel:char*:name:: +PyImport_ImportModuleLevel:const char*:name:: PyImport_ImportModuleLevel:PyObject*:globals:0:??? PyImport_ImportModuleLevel:PyObject*:locals:0:??? PyImport_ImportModuleLevel:PyObject*:fromlist:0:??? @@ -697,7 +697,7 @@ PyMapping_DelItemString:int::: PyMapping_DelItemString:PyObject*:o:0: -PyMapping_DelItemString:char*:key:: +PyMapping_DelItemString:const char*:key:: PyMapping_GetItemString:PyObject*::+1: PyMapping_GetItemString:PyObject*:o:0: @@ -767,10 +767,10 @@ PyModule_GetDict:PyObject*::0: PyModule_GetDict::PyObject* module:0: -PyModule_GetFilename:char*::: +PyModule_GetFilename:const char*::: PyModule_GetFilename:PyObject*:module:0: -PyModule_GetName:char*::: +PyModule_GetName:const char*::: PyModule_GetName:PyObject*:module:0: PyModule_New:PyObject*::+1: @@ -954,7 +954,7 @@ PyObject_DelAttrString:int::: PyObject_DelAttrString:PyObject*:o:0: -PyObject_DelAttrString:char*:attr_name:: +PyObject_DelAttrString:const char*:attr_name:: PyObject_DelItem:int::: PyObject_DelItem:PyObject*:o:0: @@ -969,7 +969,7 @@ PyObject_GetAttrString:PyObject*::+1: PyObject_GetAttrString:PyObject*:o:0: -PyObject_GetAttrString:char*:attr_name:: +PyObject_GetAttrString:const char*:attr_name:: PyObject_GetItem:PyObject*::+1: PyObject_GetItem:PyObject*:o:0: @@ -984,7 +984,7 @@ PyObject_HasAttrString:int::: PyObject_HasAttrString:PyObject*:o:0: -PyObject_HasAttrString:char*:attr_name:0: +PyObject_HasAttrString:const char*:attr_name:0: PyObject_Hash:int::: PyObject_Hash:PyObject*:o:0: @@ -1034,7 +1034,7 @@ PyObject_SetAttrString:int::: PyObject_SetAttrString:PyObject*:o:0: -PyObject_SetAttrString:char*:attr_name:: +PyObject_SetAttrString:const char*:attr_name:: PyObject_SetAttrString:PyObject*:v:+1: PyObject_SetItem:int::: @@ -1053,27 +1053,27 @@ PyParser_SimpleParseFile:struct _node*::: PyParser_SimpleParseFile:FILE*:fp:: -PyParser_SimpleParseFile:char*:filename:: +PyParser_SimpleParseFile:const char*:filename:: PyParser_SimpleParseFile:int:start:: PyParser_SimpleParseString:struct _node*::: -PyParser_SimpleParseString:char*:str:: +PyParser_SimpleParseString:const char*:str:: PyParser_SimpleParseString:int:start:: PyRun_AnyFile:int::: PyRun_AnyFile:FILE*:fp:: -PyRun_AnyFile:char*:filename:: +PyRun_AnyFile:const char*:filename:: PyRun_File:PyObject*::+1:??? -- same as eval_code2() PyRun_File:FILE*:fp:: -PyRun_File:char*:filename:: +PyRun_File:const char*:filename:: PyRun_File:int:start:: PyRun_File:PyObject*:globals:0: PyRun_File:PyObject*:locals:0: PyRun_FileEx:PyObject*::+1:??? -- same as eval_code2() PyRun_FileEx:FILE*:fp:: -PyRun_FileEx:char*:filename:: +PyRun_FileEx:const char*:filename:: PyRun_FileEx:int:start:: PyRun_FileEx:PyObject*:globals:0: PyRun_FileEx:PyObject*:locals:0: @@ -1081,7 +1081,7 @@ PyRun_FileFlags:PyObject*::+1:??? -- same as eval_code2() PyRun_FileFlags:FILE*:fp:: -PyRun_FileFlags:char*:filename:: +PyRun_FileFlags:const char*:filename:: PyRun_FileFlags:int:start:: PyRun_FileFlags:PyObject*:globals:0: PyRun_FileFlags:PyObject*:locals:0: @@ -1089,7 +1089,7 @@ PyRun_FileExFlags:PyObject*::+1:??? -- same as eval_code2() PyRun_FileExFlags:FILE*:fp:: -PyRun_FileExFlags:char*:filename:: +PyRun_FileExFlags:const char*:filename:: PyRun_FileExFlags:int:start:: PyRun_FileExFlags:PyObject*:globals:0: PyRun_FileExFlags:PyObject*:locals:0: @@ -1098,27 +1098,27 @@ PyRun_InteractiveLoop:int::: PyRun_InteractiveLoop:FILE*:fp:: -PyRun_InteractiveLoop:char*:filename:: +PyRun_InteractiveLoop:const char*:filename:: PyRun_InteractiveOne:int::: PyRun_InteractiveOne:FILE*:fp:: -PyRun_InteractiveOne:char*:filename:: +PyRun_InteractiveOne:const char*:filename:: PyRun_SimpleFile:int::: PyRun_SimpleFile:FILE*:fp:: -PyRun_SimpleFile:char*:filename:: +PyRun_SimpleFile:const char*:filename:: PyRun_SimpleString:int::: -PyRun_SimpleString:char*:command:: +PyRun_SimpleString:const char*:command:: PyRun_String:PyObject*::+1:??? -- same as eval_code2() -PyRun_String:char*:str:: +PyRun_String:const char*:str:: PyRun_String:int:start:: PyRun_String:PyObject*:globals:0: PyRun_String:PyObject*:locals:0: PyRun_StringFlags:PyObject*::+1:??? -- same as eval_code2() -PyRun_StringFlags:char*:str:: +PyRun_StringFlags:const char*:str:: PyRun_StringFlags:int:start:: PyRun_StringFlags:PyObject*:globals:0: PyRun_StringFlags:PyObject*:locals:0: @@ -1234,7 +1234,7 @@ PySlice_New:PyObject*:stop:0: PySlice_New:PyObject*:step:0: -PyString_AS_STRING:char*::: +PyString_AS_STRING:const char*::: PyString_AS_STRING:PyObject*:string:0: PyString_AsDecodedObject:PyObject*::+1: @@ -1247,7 +1247,7 @@ PyString_AsEncodedObject:const char*:encoding:: PyString_AsEncodedObject:const char*:errors:: -PyString_AsString:char*::: +PyString_AsString:const char*::: PyString_AsString:PyObject*:string:0: PyString_AsStringAndSize:int::: @@ -1315,13 +1315,13 @@ PyString_AsEncodedString:const char*:errors:: PySys_AddWarnOption:void::: -PySys_AddWarnOption:char*:s:: +PySys_AddWarnOption:const char*:s:: PySys_AddXOption:void::: PySys_AddXOption:const wchar_t*:s:: PySys_GetObject:PyObject*::0: -PySys_GetObject:char*:name:: +PySys_GetObject:const char*:name:: PySys_GetXOptions:PyObject*::0: @@ -1330,16 +1330,16 @@ PySys_SetArgv:char**:argv:: PySys_SetObject:int::: -PySys_SetObject:char*:name:: +PySys_SetObject:const char*:name:: PySys_SetObject:PyObject*:v:+1: PySys_ResetWarnOptions:void::: PySys_WriteStdout:void::: -PySys_WriteStdout:char*:format:: +PySys_WriteStdout:const char*:format:: PySys_WriteStderr:void::: -PySys_WriteStderr:char*:format:: +PySys_WriteStderr:const char*:format:: PyThreadState_Clear:void::: PyThreadState_Clear:PyThreadState*:tstate:: @@ -1719,16 +1719,16 @@ Py_AtExit:void (*)():func:: Py_BuildValue:PyObject*::+1: -Py_BuildValue:char*:format:: +Py_BuildValue:const char*:format:: Py_CompileString:PyObject*::+1: -Py_CompileString:char*:str:: -Py_CompileString:char*:filename:: +Py_CompileString:const char*:str:: +Py_CompileString:const char*:filename:: Py_CompileString:int:start:: Py_CompileStringFlags:PyObject*::+1: -Py_CompileStringFlags:char*:str:: -Py_CompileStringFlags:char*:filename:: +Py_CompileStringFlags:const char*:str:: +Py_CompileStringFlags:const char*:filename:: Py_CompileStringFlags:int:start:: Py_CompileStringFlags:PyCompilerFlags*:flags:: @@ -1742,33 +1742,33 @@ Py_Exit:int:status:: Py_FatalError:void::: -Py_FatalError:char*:message:: +Py_FatalError:const char*:message:: Py_FdIsInteractive:int::: Py_FdIsInteractive:FILE*:fp:: -Py_FdIsInteractive:char*:filename:: +Py_FdIsInteractive:const char*:filename:: Py_Finalize:void::: -Py_GetBuildInfoconst:char*::: +Py_GetBuildInfoconst:const char*::: -Py_GetCompilerconst:char*::: +Py_GetCompilerconst:const char*::: -Py_GetCopyrightconst:char*::: +Py_GetCopyrightconst:const char*::: -Py_GetExecPrefix:char*::: +Py_GetExecPrefix:const char*::: -Py_GetPath:char*::: +Py_GetPath:const char*::: -Py_GetPlatformconst:char*::: +Py_GetPlatformconst:const char*::: -Py_GetPrefix:char*::: +Py_GetPrefix:const char*::: -Py_GetProgramFullPath:char*::: +Py_GetProgramFullPath:const char*::: -Py_GetProgramName:char*::: +Py_GetProgramName:const char*::: -Py_GetVersionconst:char*::: +Py_GetVersionconst:const char*::: Py_INCREF:void::: Py_INCREF:PyObject*:o:+1: @@ -1780,7 +1780,7 @@ Py_NewInterpreter:PyThreadState*::: Py_SetProgramName:void::: -Py_SetProgramName:char*:name:: +Py_SetProgramName:const char*:name:: Py_XDECREF:void::: Py_XDECREF:PyObject*:o:-1:if o is not NULL @@ -1789,14 +1789,14 @@ Py_XINCREF:PyObject*:o:+1:if o is not NULL _PyImport_FindExtension:PyObject*::0:??? see PyImport_AddModule -_PyImport_FindExtension:char*::: -_PyImport_FindExtension:char*::: +_PyImport_FindExtension:const char*::: +_PyImport_FindExtension:const char*::: _PyImport_Fini:void::: _PyImport_FixupExtension:PyObject*:::??? -_PyImport_FixupExtension:char*::: -_PyImport_FixupExtension:char*::: +_PyImport_FixupExtension:const char*::: +_PyImport_FixupExtension:const char*::: _PyImport_Init:void::: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 21:31:14 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 21:31:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3ODcy?= =?utf-8?q?=3A_Fix_a_segfault_in_marshal=2Eload=28=29_when_input_stream_re?= =?utf-8?q?turns?= Message-ID: <3brnSL6HHPz7LjP@mail.python.org> http://hg.python.org/cpython/rev/fc7bab8a8618 changeset: 84556:fc7bab8a8618 branch: 3.3 parent: 84554:ffe24e3e7a2a user: Serhiy Storchaka date: Thu Jul 11 22:20:47 2013 +0300 summary: Issue #17872: Fix a segfault in marshal.load() when input stream returns more bytes than requested. files: Lib/test/test_marshal.py | 12 +++++++++ Misc/NEWS | 3 ++ Python/marshal.c | 35 ++++++++++++++++------------ 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -2,6 +2,7 @@ from test import support import array +import io import marshal import sys import unittest @@ -279,6 +280,17 @@ unicode_string = 'T' self.assertRaises(TypeError, marshal.loads, unicode_string) + def test_bad_reader(self): + class BadReader(io.BytesIO): + def read(self, n=-1): + b = super().read(n) + if n is not None and n > 4: + b += b' ' * 10**6 + return b + for value in (1.0, 1j, b'0123456789', '0123456789'): + self.assertRaises(ValueError, marshal.load, + BadReader(marshal.dumps(value))) + LARGE_SIZE = 2**31 pointer_size = 8 if sys.maxsize > 0xFFFFFFFF else 4 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #17872: Fix a segfault in marshal.load() when input stream returns + more bytes than requested. + - Issue #18426: Fix NULL pointer dereference in C extension import when PyModule_GetDef() returns an error. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -490,8 +490,17 @@ else { read = PyBytes_GET_SIZE(data); if (read > 0) { - ptr = PyBytes_AS_STRING(data); - memcpy(s, ptr, read); + if (read > n) { + PyErr_Format(PyExc_ValueError, + "read() returned too much data: " + "%zd bytes requested, %zd returned", + n, read); + read = -1; + } + else { + ptr = PyBytes_AS_STRING(data); + memcpy(s, ptr, read); + } } } Py_DECREF(data); @@ -733,11 +742,13 @@ double dx; retval = NULL; n = r_byte(p); - if (n == EOF || r_string(buf, n, p) != n) { + if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } + if (r_string(buf, n, p) != n) + break; buf[n] = '\0'; dx = PyOS_string_to_double(buf, NULL, NULL); if (dx == -1.0 && PyErr_Occurred()) @@ -751,8 +762,6 @@ unsigned char buf[8]; double x; if (r_string((char*)buf, 8, p) != 8) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -771,21 +780,25 @@ Py_complex c; retval = NULL; n = r_byte(p); - if (n == EOF || r_string(buf, n, p) != n) { + if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } + if (r_string(buf, n, p) != n) + break; buf[n] = '\0'; c.real = PyOS_string_to_double(buf, NULL, NULL); if (c.real == -1.0 && PyErr_Occurred()) break; n = r_byte(p); - if (n == EOF || r_string(buf, n, p) != n) { + if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } + if (r_string(buf, n, p) != n) + break; buf[n] = '\0'; c.imag = PyOS_string_to_double(buf, NULL, NULL); if (c.imag == -1.0 && PyErr_Occurred()) @@ -799,8 +812,6 @@ unsigned char buf[8]; Py_complex c; if (r_string((char*)buf, 8, p) != 8) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -810,8 +821,6 @@ break; } if (r_string((char*)buf, 8, p) != 8) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -842,8 +851,6 @@ } if (r_string(PyBytes_AS_STRING(v), n, p) != n) { Py_DECREF(v); - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -871,8 +878,6 @@ } if (r_string(buffer, n, p) != n) { PyMem_DEL(buffer); - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 21:31:16 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 11 Jul 2013 21:31:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317872=3A_Fix_a_segfault_in_marshal=2Eload=28=29?= =?utf-8?q?_when_input_stream_returns?= Message-ID: <3brnSN2mQ3z7LjT@mail.python.org> http://hg.python.org/cpython/rev/5fa793ae36cc changeset: 84557:5fa793ae36cc parent: 84555:6587fd3d89ae parent: 84556:fc7bab8a8618 user: Serhiy Storchaka date: Thu Jul 11 22:28:18 2013 +0300 summary: Issue #17872: Fix a segfault in marshal.load() when input stream returns more bytes than requested. files: Lib/test/test_marshal.py | 12 +++++++++ Misc/NEWS | 3 ++ Python/marshal.c | 35 ++++++++++++++++------------ 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -2,6 +2,7 @@ from test import support import array +import io import marshal import sys import unittest @@ -259,6 +260,17 @@ unicode_string = 'T' self.assertRaises(TypeError, marshal.loads, unicode_string) + def test_bad_reader(self): + class BadReader(io.BytesIO): + def read(self, n=-1): + b = super().read(n) + if n is not None and n > 4: + b += b' ' * 10**6 + return b + for value in (1.0, 1j, b'0123456789', '0123456789'): + self.assertRaises(ValueError, marshal.load, + BadReader(marshal.dumps(value))) + def _test_eof(self): data = marshal.dumps(("hello", "dolly", None)) for i in range(len(data)): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #17872: Fix a segfault in marshal.load() when input stream returns + more bytes than requested. + - Issue #18338: `python --version` now prints version string to stdout, and not to stderr. Patch by Berker Peksag and Michael Dickens. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -570,8 +570,17 @@ else { read = (int)PyBytes_GET_SIZE(data); if (read > 0) { - ptr = PyBytes_AS_STRING(data); - memcpy(s, ptr, read); + if (read > n) { + PyErr_Format(PyExc_ValueError, + "read() returned too much data: " + "%zd bytes requested, %zd returned", + n, read); + read = -1; + } + else { + ptr = PyBytes_AS_STRING(data); + memcpy(s, ptr, read); + } } } Py_DECREF(data); @@ -841,11 +850,13 @@ double dx; retval = NULL; n = r_byte(p); - if (n == EOF || r_string(buf, n, p) != n) { + if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } + if (r_string(buf, n, p) != n) + break; buf[n] = '\0'; dx = PyOS_string_to_double(buf, NULL, NULL); if (dx == -1.0 && PyErr_Occurred()) @@ -860,8 +871,6 @@ unsigned char buf[8]; double x; if (r_string((char*)buf, 8, p) != 8) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -881,21 +890,25 @@ Py_complex c; retval = NULL; n = r_byte(p); - if (n == EOF || r_string(buf, n, p) != n) { + if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } + if (r_string(buf, n, p) != n) + break; buf[n] = '\0'; c.real = PyOS_string_to_double(buf, NULL, NULL); if (c.real == -1.0 && PyErr_Occurred()) break; n = r_byte(p); - if (n == EOF || r_string(buf, n, p) != n) { + if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } + if (r_string(buf, n, p) != n) + break; buf[n] = '\0'; c.imag = PyOS_string_to_double(buf, NULL, NULL); if (c.imag == -1.0 && PyErr_Occurred()) @@ -910,8 +923,6 @@ unsigned char buf[8]; Py_complex c; if (r_string((char*)buf, 8, p) != 8) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -921,8 +932,6 @@ break; } if (r_string((char*)buf, 8, p) != 8) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -954,8 +963,6 @@ } if (r_string(PyBytes_AS_STRING(v), n, p) != n) { Py_DECREF(v); - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -986,8 +993,6 @@ } if (r_string(buffer, n, p) != n) { PyMem_DEL(buffer); - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 21:59:05 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 11 Jul 2013 21:59:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4MDQ0OiBGaXgg?= =?utf-8?q?parsing_of_encoded_words_of_the_form_=3D=3Futf8=3Fq=3F=3DXX=2E?= =?utf-8?b?Li4/PQ==?= Message-ID: <3brp4T0rH1z7Ljn@mail.python.org> http://hg.python.org/cpython/rev/4acb822f4c43 changeset: 84558:4acb822f4c43 branch: 3.3 parent: 84556:fc7bab8a8618 user: R David Murray date: Thu Jul 11 15:52:57 2013 -0400 summary: #18044: Fix parsing of encoded words of the form =?utf8?q?=XX...?= The problem was I was only checking for decimal digits after the third '?', not for *hex* digits :(. This changeset also fixes a couple of comment typos, deletes an unused function relating to encoded word parsing, and removed an invalid 'if' test from the folding function that was revealed by the tests written to validate this issue. files: Lib/email/_header_value_parser.py | 43 +-------- Lib/test/test_email/test__encoded_words.py | 5 + Lib/test/test_email/test__header_value_parser.py | 9 ++ Lib/test/test_email/test_headerregistry.py | 41 ++++++++- Misc/NEWS | 4 + 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -69,6 +69,7 @@ import re import urllib # For urllib.parse.unquote +from string import hexdigits from collections import namedtuple, OrderedDict from email import _encoded_words as _ew from email import errors @@ -392,10 +393,6 @@ token_type = 'unstructured' def _fold(self, folded): - if any(x.token_type=='encoded-word' for x in self): - return self._fold_encoded(folded) - # Here we can have either a pure ASCII string that may or may not - # have surrogateescape encoded bytes, or a unicode string. last_ew = None for part in self.parts: tstr = str(part) @@ -1389,35 +1386,6 @@ pos = pos + 1 return ''.join(vchars), ''.join([fragment[pos:]] + remainder), had_qp -def _decode_ew_run(value): - """ Decode a run of RFC2047 encoded words. - - _decode_ew_run(value) -> (text, value, defects) - - Scans the supplied value for a run of tokens that look like they are RFC - 2047 encoded words, decodes those words into text according to RFC 2047 - rules (whitespace between encoded words is discarded), and returns the text - and the remaining value (including any leading whitespace on the remaining - value), as well as a list of any defects encountered while decoding. The - input value may not have any leading whitespace. - - """ - res = [] - defects = [] - last_ws = '' - while value: - try: - tok, ws, value = _wsp_splitter(value, 1) - except ValueError: - tok, ws, value = value, '', '' - if not (tok.startswith('=?') and tok.endswith('?=')): - return ''.join(res), last_ws + tok + ws + value, defects - text, charset, lang, new_defects = _ew.decode(tok) - res.append(text) - defects.extend(new_defects) - last_ws = ws - return ''.join(res), last_ws, defects - def get_fws(value): """FWS = 1*WSP @@ -1443,7 +1411,8 @@ raise errors.HeaderParseError( "expected encoded word but found {}".format(value)) remstr = ''.join(remainder) - if remstr[:2].isdigit(): + if len(remstr) > 1 and remstr[0] in hexdigits and remstr[1] in hexdigits: + # The ? after the CTE was followed by an encoded word escape (=XX). rest, *remainder = remstr.split('?=', 1) tok = tok + '?=' + rest if len(tok.split()) > 1: @@ -1491,8 +1460,8 @@ """ # XXX: but what about bare CR and LF? They might signal the start or - # end of an encoded word. YAGNI for now, since out current parsers - # will never send us strings with bard CR or LF. + # end of an encoded word. YAGNI for now, since our current parsers + # will never send us strings with bare CR or LF. unstructured = UnstructuredTokenList() while value: @@ -1504,6 +1473,8 @@ try: token, value = get_encoded_word(value) except errors.HeaderParseError: + # XXX: Need to figure out how to register defects when + # appropriate here. pass else: have_ws = True diff --git a/Lib/test/test_email/test__encoded_words.py b/Lib/test/test_email/test__encoded_words.py --- a/Lib/test/test_email/test__encoded_words.py +++ b/Lib/test/test_email/test__encoded_words.py @@ -122,6 +122,11 @@ # XXX Should this be a new Defect instead? defects = [errors.CharsetError]) + def test_q_nonascii(self): + self._test('=?utf-8?q?=C3=89ric?=', + '?ric', + charset='utf-8') + class TestEncodeQ(TestEmailBase): diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -170,6 +170,15 @@ [], '') + def test_get_encoded_word_quopri_utf_escape_follows_cte(self): + # Issue 18044 + self._test_get_x(parser.get_encoded_word, + '=?utf-8?q?=C3=89ric?=', + '?ric', + '?ric', + [], + '') + # get_unstructured def _get_unst(self, value): diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -123,12 +123,45 @@ # self.assertEqual(h, value) # self.assertDefectsEqual(h.defects, [errors.ObsoleteHeaderDefect]) - def test_RFC2047_value_decoded(self): - value = '=?utf-8?q?this_is_a_test?=' - h = self.make_header('subject', value) - self.assertEqual(h, 'this is a test') + at parameterize +class TestUnstructuredHeader(TestHeaderBase): + def string_as_value(self, + source, + decoded, + *args): + l = len(args) + defects = args[0] if l>0 else [] + header = 'Subject:' + (' ' if source else '') + folded = header + (args[1] if l>1 else source) + '\n' + h = self.make_header('Subject', source) + self.assertEqual(h, decoded) + self.assertDefectsEqual(h.defects, defects) + self.assertEqual(h.fold(policy=policy.default), folded) + + string_params = { + + 'rfc2047_simple_quopri': ( + '=?utf-8?q?this_is_a_test?=', + 'this is a test', + [], + 'this is a test'), + + 'rfc2047_gb2312_base64': ( + '=?gb2312?b?1eLKx9bQzsSy4srUo6E=?=', + '\u8fd9\u662f\u4e2d\u6587\u6d4b\u8bd5\uff01', + [], + '=?utf-8?b?6L+Z5piv5Lit5paH5rWL6K+V77yB?='), + + 'rfc2047_simple_nonascii_quopri': ( + '=?utf-8?q?=C3=89ric?=', + '?ric'), + + } + + + at parameterize class TestDateHeader(TestHeaderBase): datestring = 'Sun, 23 Sep 2001 20:10:55 -0700' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,10 @@ Library ------- +- Issue #18044: The new email header parser was mis-parsing encoded words where + an encoded character immediately followed the '?' that follows the CTE + character, resulting in a decoding failure. They are now decoded correctly. + - Issue #18101: Tcl.split() now process strings nested in a tuple as it do with byte strings. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 21:59:06 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 11 Jul 2013 21:59:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_=2318044=3A_Fix_parsing_of_encoded_words_of_the?= =?utf-8?b?IGZvcm0gPT91dGY4P3E/PVhYLi4uPz0=?= Message-ID: <3brp4V4sW1z7Ljn@mail.python.org> http://hg.python.org/cpython/rev/32c6cfffbddd changeset: 84559:32c6cfffbddd parent: 84557:5fa793ae36cc parent: 84558:4acb822f4c43 user: R David Murray date: Thu Jul 11 15:58:07 2013 -0400 summary: Merge: #18044: Fix parsing of encoded words of the form =?utf8?q?=XX...?= files: Lib/email/_header_value_parser.py | 43 +-------- Lib/test/test_email/test__encoded_words.py | 5 + Lib/test/test_email/test__header_value_parser.py | 9 ++ Lib/test/test_email/test_headerregistry.py | 41 ++++++++- Misc/NEWS | 4 + 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -69,6 +69,7 @@ import re import urllib # For urllib.parse.unquote +from string import hexdigits from collections import namedtuple, OrderedDict from email import _encoded_words as _ew from email import errors @@ -391,10 +392,6 @@ token_type = 'unstructured' def _fold(self, folded): - if any(x.token_type=='encoded-word' for x in self): - return self._fold_encoded(folded) - # Here we can have either a pure ASCII string that may or may not - # have surrogateescape encoded bytes, or a unicode string. last_ew = None for part in self.parts: tstr = str(part) @@ -1386,35 +1383,6 @@ pos = pos + 1 return ''.join(vchars), ''.join([fragment[pos:]] + remainder), had_qp -def _decode_ew_run(value): - """ Decode a run of RFC2047 encoded words. - - _decode_ew_run(value) -> (text, value, defects) - - Scans the supplied value for a run of tokens that look like they are RFC - 2047 encoded words, decodes those words into text according to RFC 2047 - rules (whitespace between encoded words is discarded), and returns the text - and the remaining value (including any leading whitespace on the remaining - value), as well as a list of any defects encountered while decoding. The - input value may not have any leading whitespace. - - """ - res = [] - defects = [] - last_ws = '' - while value: - try: - tok, ws, value = _wsp_splitter(value, 1) - except ValueError: - tok, ws, value = value, '', '' - if not (tok.startswith('=?') and tok.endswith('?=')): - return ''.join(res), last_ws + tok + ws + value, defects - text, charset, lang, new_defects = _ew.decode(tok) - res.append(text) - defects.extend(new_defects) - last_ws = ws - return ''.join(res), last_ws, defects - def get_fws(value): """FWS = 1*WSP @@ -1440,7 +1408,8 @@ raise errors.HeaderParseError( "expected encoded word but found {}".format(value)) remstr = ''.join(remainder) - if remstr[:2].isdigit(): + if len(remstr) > 1 and remstr[0] in hexdigits and remstr[1] in hexdigits: + # The ? after the CTE was followed by an encoded word escape (=XX). rest, *remainder = remstr.split('?=', 1) tok = tok + '?=' + rest if len(tok.split()) > 1: @@ -1488,8 +1457,8 @@ """ # XXX: but what about bare CR and LF? They might signal the start or - # end of an encoded word. YAGNI for now, since out current parsers - # will never send us strings with bard CR or LF. + # end of an encoded word. YAGNI for now, since our current parsers + # will never send us strings with bare CR or LF. unstructured = UnstructuredTokenList() while value: @@ -1501,6 +1470,8 @@ try: token, value = get_encoded_word(value) except errors.HeaderParseError: + # XXX: Need to figure out how to register defects when + # appropriate here. pass else: have_ws = True diff --git a/Lib/test/test_email/test__encoded_words.py b/Lib/test/test_email/test__encoded_words.py --- a/Lib/test/test_email/test__encoded_words.py +++ b/Lib/test/test_email/test__encoded_words.py @@ -122,6 +122,11 @@ # XXX Should this be a new Defect instead? defects = [errors.CharsetError]) + def test_q_nonascii(self): + self._test('=?utf-8?q?=C3=89ric?=', + '?ric', + charset='utf-8') + class TestEncodeQ(TestEmailBase): diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -170,6 +170,15 @@ [], '') + def test_get_encoded_word_quopri_utf_escape_follows_cte(self): + # Issue 18044 + self._test_get_x(parser.get_encoded_word, + '=?utf-8?q?=C3=89ric?=', + '?ric', + '?ric', + [], + '') + # get_unstructured def _get_unst(self, value): diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -123,12 +123,45 @@ # self.assertEqual(h, value) # self.assertDefectsEqual(h.defects, [errors.ObsoleteHeaderDefect]) - def test_RFC2047_value_decoded(self): - value = '=?utf-8?q?this_is_a_test?=' - h = self.make_header('subject', value) - self.assertEqual(h, 'this is a test') + at parameterize +class TestUnstructuredHeader(TestHeaderBase): + def string_as_value(self, + source, + decoded, + *args): + l = len(args) + defects = args[0] if l>0 else [] + header = 'Subject:' + (' ' if source else '') + folded = header + (args[1] if l>1 else source) + '\n' + h = self.make_header('Subject', source) + self.assertEqual(h, decoded) + self.assertDefectsEqual(h.defects, defects) + self.assertEqual(h.fold(policy=policy.default), folded) + + string_params = { + + 'rfc2047_simple_quopri': ( + '=?utf-8?q?this_is_a_test?=', + 'this is a test', + [], + 'this is a test'), + + 'rfc2047_gb2312_base64': ( + '=?gb2312?b?1eLKx9bQzsSy4srUo6E=?=', + '\u8fd9\u662f\u4e2d\u6587\u6d4b\u8bd5\uff01', + [], + '=?utf-8?b?6L+Z5piv5Lit5paH5rWL6K+V77yB?='), + + 'rfc2047_simple_nonascii_quopri': ( + '=?utf-8?q?=C3=89ric?=', + '?ric'), + + } + + + at parameterize class TestDateHeader(TestHeaderBase): datestring = 'Sun, 23 Sep 2001 20:10:55 -0700' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -151,6 +151,10 @@ Library ------- +- Issue #18044: The new email header parser was mis-parsing encoded words where + an encoded character immediately followed the '?' that follows the CTE + character, resulting in a decoding failure. They are now decoded correctly. + - Issue #18101: Tcl.split() now process strings nested in a tuple as it do with byte strings. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 22:46:47 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 22:46:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_typeobject=2Ec=3A_remove_t?= =?utf-8?q?railing_spaces?= Message-ID: <3brq7W0WT0zRSp@mail.python.org> http://hg.python.org/cpython/rev/a2d6274e2fc8 changeset: 84560:a2d6274e2fc8 user: Victor Stinner date: Thu Jul 11 22:42:25 2013 +0200 summary: typeobject.c: remove trailing spaces files: Objects/typeobject.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2411,7 +2411,7 @@ char *s; char *res_start = (char*)res; PyType_Slot *slot; - + /* Set the type name and qualname */ s = strrchr(spec->name, '.'); if (s == NULL) @@ -2432,7 +2432,7 @@ type->tp_name = spec->name; if (!type->tp_name) goto fail; - + /* Adjust for empty tuple bases */ if (!bases) { base = &PyBaseObject_Type; @@ -2516,7 +2516,7 @@ /* Set type.__module__ */ s = strrchr(spec->name, '.'); if (s != NULL) - _PyDict_SetItemId(type->tp_dict, &PyId___module__, + _PyDict_SetItemId(type->tp_dict, &PyId___module__, PyUnicode_FromStringAndSize( spec->name, (Py_ssize_t)(s - spec->name))); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 22:46:48 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 22:46:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_slot=5Ft?= =?utf-8?q?p=5Fstr=28=29_must_not_fallback_on_slot=5Ftp=5Frepr=28=29_on_er?= =?utf-8?q?ror?= Message-ID: <3brq7X3v1Dz7LjT@mail.python.org> http://hg.python.org/cpython/rev/01a46dc00fc8 changeset: 84561:01a46dc00fc8 user: Victor Stinner date: Thu Jul 11 22:46:11 2013 +0200 summary: Issue #18408: slot_tp_str() must not fallback on slot_tp_repr() on error type->tp_str must not point to slot_tp_str() if type has no __str__ attribute, so there is no reason for slot_tp_str() to fallback on slot_tp_str() on lookup error. Moreover, calling PyErr_Clear() may hide a real bug like MemoryError. If __str__ attribute is removed, slots must be updated (which is done by type_setattro()). files: Objects/typeobject.c | 21 ++------------------- 1 files changed, 2 insertions(+), 19 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5274,29 +5274,12 @@ _Py_IDENTIFIER(__str__); func = lookup_method(self, &PyId___str__); - if (func != NULL) { + if (func == NULL) + return NULL; res = PyEval_CallObject(func, NULL); Py_DECREF(func); return res; } - else { - /* PyObject *ress; */ - PyErr_Clear(); - res = slot_tp_repr(self); - if (!res) - return NULL; - /* XXX this is non-sensical. Why should we return - a bytes object from __str__. Is this code even - used? - mvl */ - assert(0); - return res; - /* - ress = _PyUnicode_AsDefaultEncodedString(res); - Py_DECREF(res); - return ress; - */ - } -} static Py_hash_t slot_tp_hash(PyObject *self) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 23:12:09 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 23:12:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_ste=5Fne?= =?utf-8?q?w=28=29_initialize_all_attributes_before_handling_error?= Message-ID: <3brqhn2MrDz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/39eb1ce5f377 changeset: 84562:39eb1ce5f377 user: Victor Stinner date: Thu Jul 11 22:49:00 2013 +0200 summary: Issue #18408: ste_new() initialize all attributes before handling error If an attribute is not initialized, the destructor can crash files: Python/symtable.c | 22 +++++++++------------- 1 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -37,25 +37,13 @@ ste->ste_table = st; ste->ste_id = k; /* ste owns reference to k */ + Py_INCREF(name); ste->ste_name = name; - Py_INCREF(name); ste->ste_symbols = NULL; ste->ste_varnames = NULL; ste->ste_children = NULL; - ste->ste_symbols = PyDict_New(); - if (ste->ste_symbols == NULL) - goto fail; - - ste->ste_varnames = PyList_New(0); - if (ste->ste_varnames == NULL) - goto fail; - - ste->ste_children = PyList_New(0); - if (ste->ste_children == NULL) - goto fail; - ste->ste_directives = NULL; ste->ste_type = block; @@ -79,6 +67,14 @@ ste->ste_returns_value = 0; ste->ste_needs_class_closure = 0; + ste->ste_symbols = PyDict_New(); + ste->ste_varnames = PyList_New(0); + ste->ste_children = PyList_New(0); + if (ste->ste_symbols == NULL + || ste->ste_varnames == NULL + || ste->ste_children == NULL) + goto fail; + if (PyDict_SetItem(st->st_blocks, ste->ste_id, (PyObject *)ste) < 0) goto fail; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 23:12:10 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 23:12:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_comp?= =?utf-8?q?iler=5Fimport=28=29_to_handle_PyUnicode=5FSubstring=28=29_failu?= =?utf-8?q?re?= Message-ID: <3brqhp4YNPz7Ljq@mail.python.org> http://hg.python.org/cpython/rev/aaa6e8b8a5c9 changeset: 84563:aaa6e8b8a5c9 user: Victor Stinner date: Thu Jul 11 22:50:45 2013 +0200 summary: Issue #18408: Fix compiler_import() to handle PyUnicode_Substring() failure properly files: Python/compile.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -2316,8 +2316,11 @@ identifier tmp = alias->name; Py_ssize_t dot = PyUnicode_FindChar( alias->name, '.', 0, PyUnicode_GET_LENGTH(alias->name), 1); - if (dot != -1) + if (dot != -1) { tmp = PyUnicode_Substring(alias->name, 0, dot); + if (tmp == NULL) + return 0; + } r = compiler_nameop(c, tmp, Store); if (dot != -1) { Py_DECREF(tmp); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 23:12:11 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 23:12:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_parsetok?= =?utf-8?q?=28=29_must_not_write_into_stderr_on_memory_allocation_error?= Message-ID: <3brqhq6b33z7Ljr@mail.python.org> http://hg.python.org/cpython/rev/ff93930a53c0 changeset: 84564:ff93930a53c0 user: Victor Stinner date: Thu Jul 11 22:52:19 2013 +0200 summary: Issue #18408: parsetok() must not write into stderr on memory allocation error The caller gets an error code and can raise a classic Python exception. files: Parser/parsetok.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Parser/parsetok.c b/Parser/parsetok.c --- a/Parser/parsetok.c +++ b/Parser/parsetok.c @@ -178,7 +178,6 @@ len = b - a; /* XXX this may compute NULL - NULL */ str = (char *) PyObject_MALLOC(len + 1); if (str == NULL) { - fprintf(stderr, "no mem for next token\n"); err_ret->error = E_NOMEM; break; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 23:12:13 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 23:12:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_=5FP?= =?utf-8?q?ickler=5FNew=28=29_and_=5FUnpickler=5FNew=28=29=3A_initialize_a?= =?utf-8?q?ll?= Message-ID: <3brqhs1j27z7LjQ@mail.python.org> http://hg.python.org/cpython/rev/1a1869baec4c changeset: 84565:1a1869baec4c user: Victor Stinner date: Thu Jul 11 22:56:25 2013 +0200 summary: Issue #18408: Fix _Pickler_New() and _Unpickler_New(): initialize all attributes before handling errors _Pickler_New() now calls PyObject_GC_Del() instead of Py_DECREF() on error, because the pickle object is created using PyObject_GC_New(). Fix a crash in the destructor when an attribute is not initiallized. files: Modules/_pickle.c | 36 +++++++++++++--------------------- 1 files changed, 14 insertions(+), 22 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -774,18 +774,15 @@ self->fast_nesting = 0; self->fix_imports = 0; self->fast_memo = NULL; - - self->memo = PyMemoTable_New(); - if (self->memo == NULL) { - Py_DECREF(self); - return NULL; - } self->max_output_len = WRITE_BUF_SIZE; self->output_len = 0; + + self->memo = PyMemoTable_New(); self->output_buffer = PyBytes_FromStringAndSize(NULL, self->max_output_len); - if (self->output_buffer == NULL) { - Py_DECREF(self); + + if (self->memo == NULL || self->output_buffer == NULL) { + PyObject_GC_Del(self); return NULL; } return self; @@ -1136,20 +1133,6 @@ if (self == NULL) return NULL; - self->stack = (Pdata *)Pdata_New(); - if (self->stack == NULL) { - Py_DECREF(self); - return NULL; - } - memset(&self->buffer, 0, sizeof(Py_buffer)); - - self->memo_size = 32; - self->memo = _Unpickler_NewMemo(self->memo_size); - if (self->memo == NULL) { - Py_DECREF(self); - return NULL; - } - self->arg = NULL; self->pers_func = NULL; self->input_buffer = NULL; @@ -1167,6 +1150,15 @@ self->marks_size = 0; self->proto = 0; self->fix_imports = 0; + memset(&self->buffer, 0, sizeof(Py_buffer)); + self->memo_size = 32; + self->memo = _Unpickler_NewMemo(self->memo_size); + self->stack = (Pdata *)Pdata_New(); + + if (self->memo == NULL || self->stack == NULL) { + Py_DECREF(self); + return NULL; + } return self; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 23:12:14 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 23:12:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_=5Feleme?= =?utf-8?q?nttree=2Ec_now_handles_create=5Fextra=28=29_failure?= Message-ID: <3brqht3x3Hz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/e11121b9bd09 changeset: 84566:e11121b9bd09 user: Victor Stinner date: Thu Jul 11 23:01:36 2013 +0200 summary: Issue #18408: _elementtree.c now handles create_extra() failure files: Modules/_elementtree.c | 36 ++++++++++++++++++++---------- 1 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -374,8 +374,10 @@ /* make sure self->children can hold the given number of extra elements. set an exception and return -1 if allocation failed */ - if (!self->extra) - create_extra(self, NULL); + if (!self->extra) { + if (create_extra(self, NULL) < 0) + return -1; + } size = self->extra->length + extra; @@ -1267,8 +1269,10 @@ &Element_Type, &element)) return NULL; - if (!self->extra) - create_extra(self, NULL); + if (!self->extra) { + if (create_extra(self, NULL) < 0) + return NULL; + } if (index < 0) { index += self->extra->length; @@ -1409,8 +1413,10 @@ if (!PyArg_ParseTuple(args, "OO:set", &key, &value)) return NULL; - if (!self->extra) - create_extra(self, NULL); + if (!self->extra) { + if (create_extra(self, NULL) < 0) + return NULL; + } attrib = element_get_attrib(self); if (!attrib) @@ -1525,8 +1531,10 @@ PyObject* recycle = NULL; PyObject* seq = NULL; - if (!self->extra) - create_extra(self, NULL); + if (!self->extra) { + if (create_extra(self, NULL) < 0) + return -1; + } if (PySlice_GetIndicesEx(item, self->extra->length, @@ -1756,8 +1764,10 @@ res = element_get_tail(self); } else if (strcmp(name, "attrib") == 0) { PyErr_Clear(); - if (!self->extra) - create_extra(self, NULL); + if (!self->extra) { + if (create_extra(self, NULL) < 0) + return NULL; + } res = element_get_attrib(self); } @@ -1790,8 +1800,10 @@ self->tail = value; Py_INCREF(self->tail); } else if (strcmp(name, "attrib") == 0) { - if (!self->extra) - create_extra(self, NULL); + if (!self->extra) { + if (create_extra(self, NULL) < 0) + return -1; + } Py_DECREF(self->extra->attrib); self->extra->attrib = value; Py_INCREF(self->extra->attrib); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 23:12:15 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 23:12:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Cleanup_=5Felementtree=2Ec?= Message-ID: <3brqhv60qJz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/e1b398d0decb changeset: 84567:e1b398d0decb user: Victor Stinner date: Thu Jul 11 23:05:03 2013 +0200 summary: Cleanup _elementtree.c files: Modules/_elementtree.c | 13 ++++++------- 1 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -529,7 +529,6 @@ } elem = create_new_element(tag, attrib); - Py_DECREF(attrib); if (element_add_subelement(parent, elem) < 0) { @@ -1784,10 +1783,10 @@ char *name = ""; if (PyUnicode_Check(nameobj)) name = _PyUnicode_AsString(nameobj); - - if (name == NULL) { + if (name == NULL) return -1; - } else if (strcmp(name, "tag") == 0) { + + if (strcmp(name, "tag") == 0) { Py_DECREF(self->tag); self->tag = value; Py_INCREF(self->tag); @@ -2135,15 +2134,15 @@ if (star && PyObject_RichCompareBool(tag, star, Py_EQ) == 1) tag = Py_None; - Py_XDECREF(star); + + Py_INCREF(tag); it->sought_tag = tag; it->root_done = 0; it->gettext = gettext; + Py_INCREF(self); it->root_element = self; - Py_INCREF(self); - Py_INCREF(tag); PyObject_GC_Track(it); return (PyObject *)it; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 23:12:17 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 23:12:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Differen?= =?utf-8?q?t_fixes_in_=5Felementtree=2Ec_to_handle_correctly_MemoryError?= Message-ID: <3brqhx12Hsz7LjP@mail.python.org> http://hg.python.org/cpython/rev/0877e17fa25e changeset: 84568:0877e17fa25e user: Victor Stinner date: Thu Jul 11 23:08:39 2013 +0200 summary: Issue #18408: Different fixes in _elementtree.c to handle correctly MemoryError * create_new_element() initializes all attributes before handling errors, to fix a crash in the destructor * create_new_element() calls PyObject_GC_Del() on error, instead of PyObject_Del(), because the object was created by PyObject_GC_New() * subelement() now handles create_new_element() failure * element_getattro() now handles element_get_text() failure * makeuniversal() now handles PyBytes_FromStringAndSize() failure files: Modules/_elementtree.c | 32 +++++++++++++++++------------ 1 files changed, 19 insertions(+), 13 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -224,24 +224,24 @@ return NULL; self->extra = NULL; + Py_INCREF(tag); + self->tag = tag; + + Py_INCREF(Py_None); + self->text = Py_None; + + Py_INCREF(Py_None); + self->tail = Py_None; + + self->weakreflist = NULL; + if (attrib != Py_None && !is_empty_dict(attrib)) { if (create_extra(self, attrib) < 0) { - PyObject_Del(self); + PyObject_GC_Del(self); return NULL; } } - Py_INCREF(tag); - self->tag = tag; - - Py_INCREF(Py_None); - self->text = Py_None; - - Py_INCREF(Py_None); - self->tail = Py_None; - - self->weakreflist = NULL; - ALLOC(sizeof(ElementObject), "create element"); PyObject_GC_Track(self); return (PyObject*) self; @@ -530,6 +530,8 @@ elem = create_new_element(tag, attrib); Py_DECREF(attrib); + if (elem == NULL) + return NULL; if (element_add_subelement(parent, elem) < 0) { Py_DECREF(elem); @@ -1748,7 +1750,7 @@ return res; } else if (strcmp(name, "text") == 0) { res = element_get_text(self); - Py_INCREF(res); + Py_XINCREF(res); return res; } @@ -2726,6 +2728,10 @@ if (i != size) { /* convert to universal name */ tag = PyBytes_FromStringAndSize(NULL, size+1); + if (tag == NULL) { + Py_DECREF(key); + return NULL; + } p = PyBytes_AS_STRING(tag); p[0] = '{'; memcpy(p+1, string, size); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 23:47:02 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 23:47:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_parsetok?= =?utf-8?q?=28=29_must_not_write_into_stderr_on_memory_allocation_error?= Message-ID: <3brrT24dqtzRq4@mail.python.org> http://hg.python.org/cpython/rev/51eddca9dd6f changeset: 84569:51eddca9dd6f user: Victor Stinner date: Thu Jul 11 23:17:33 2013 +0200 summary: Issue #18408: parsetok() must not write into stderr on memory allocation error The caller gets an error code and can raise a classic Python exception. files: Parser/parsetok.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Parser/parsetok.c b/Parser/parsetok.c --- a/Parser/parsetok.c +++ b/Parser/parsetok.c @@ -138,7 +138,6 @@ int started = 0; if ((ps = PyParser_New(g, start)) == NULL) { - fprintf(stderr, "no mem for new parser\n"); err_ret->error = E_NOMEM; PyTokenizer_Free(tok); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 11 23:47:03 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 11 Jul 2013 23:47:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_In_debug?= =?utf-8?q?_mode=2C_PyCFunction=5FCall=28=29_now_checks_if_an_exception_wa?= =?utf-8?q?s?= Message-ID: <3brrT36gVRz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/5e50f1a0c985 changeset: 84570:5e50f1a0c985 user: Victor Stinner date: Thu Jul 11 23:44:46 2013 +0200 summary: Issue #18408: In debug mode, PyCFunction_Call() now checks if an exception was raised if the result is NULL to help to find bugs in C mode (get the error earlier than the SystemError in ceval.c). files: Objects/methodobject.c | 30 +++++++++++++++++++++++------- 1 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Objects/methodobject.c b/Objects/methodobject.c --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -79,23 +79,34 @@ PyObject * PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { +#define CHECK_RESULT(res) assert(res != NULL || PyErr_Occurred()) + PyCFunctionObject* f = (PyCFunctionObject*)func; PyCFunction meth = PyCFunction_GET_FUNCTION(func); PyObject *self = PyCFunction_GET_SELF(func); + PyObject *res; Py_ssize_t size; switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) { case METH_VARARGS: - if (kw == NULL || PyDict_Size(kw) == 0) - return (*meth)(self, arg); + if (kw == NULL || PyDict_Size(kw) == 0) { + res = (*meth)(self, arg); + CHECK_RESULT(res); + return res; + } break; case METH_VARARGS | METH_KEYWORDS: - return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); + res = (*(PyCFunctionWithKeywords)meth)(self, arg, kw); + CHECK_RESULT(res); + return res; case METH_NOARGS: if (kw == NULL || PyDict_Size(kw) == 0) { size = PyTuple_GET_SIZE(arg); - if (size == 0) - return (*meth)(self, NULL); + if (size == 0) { + res = (*meth)(self, NULL); + CHECK_RESULT(res); + return res; + } PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", f->m_ml->ml_name, size); @@ -105,8 +116,11 @@ case METH_O: if (kw == NULL || PyDict_Size(kw) == 0) { size = PyTuple_GET_SIZE(arg); - if (size == 1) - return (*meth)(self, PyTuple_GET_ITEM(arg, 0)); + if (size == 1) { + res = (*meth)(self, PyTuple_GET_ITEM(arg, 0)); + CHECK_RESULT(res); + return res; + } PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", f->m_ml->ml_name, size); @@ -123,6 +137,8 @@ PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", f->m_ml->ml_name); return NULL; + +#undef CHECK_RESULT } /* Methods (the standard built-in methods, that is) */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 00:59:04 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 00:59:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_normaliz?= =?utf-8?q?estring=28=29_now_raises_MemoryError_on_memory_allocation?= Message-ID: <3brt484d4xz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/4975bcd67aa7 changeset: 84571:4975bcd67aa7 user: Victor Stinner date: Fri Jul 12 00:02:55 2013 +0200 summary: Issue #18408: normalizestring() now raises MemoryError on memory allocation failure files: Python/codecs.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/codecs.c b/Python/codecs.c --- a/Python/codecs.c +++ b/Python/codecs.c @@ -65,7 +65,7 @@ p = PyMem_Malloc(len + 1); if (p == NULL) - return NULL; + return PyErr_NoMemory(); for (i = 0; i < len; i++) { register char ch = string[i]; if (ch == ' ') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 00:59:05 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 00:59:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Oh=2C_I_?= =?utf-8?q?was_wrong=3A_Pickler=5FNew=28=29_must_call_Py=5FDECREF=28=29_to?= =?utf-8?q?_destroy?= Message-ID: <3brt496pprz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/1eac89af9acf changeset: 84572:1eac89af9acf user: Victor Stinner date: Fri Jul 12 00:08:59 2013 +0200 summary: Issue #18408: Oh, I was wrong: Pickler_New() must call Py_DECREF() to destroy the newly created pickler, and not PyObject_GC_Del(). files: Modules/_pickle.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -782,7 +782,7 @@ self->max_output_len); if (self->memo == NULL || self->output_buffer == NULL) { - PyObject_GC_Del(self); + Py_DECREF(self); return NULL; } return self; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 00:59:07 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 00:59:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_ceval=2E?= =?utf-8?q?c=3A_in_debug_mode=2C_convert_the_PyErr=5FOccurred=28=29_check_?= =?utf-8?q?on?= Message-ID: <3brt4C1nsKz7LkQ@mail.python.org> http://hg.python.org/cpython/rev/d9446c2a2fd4 changeset: 84573:d9446c2a2fd4 user: Victor Stinner date: Fri Jul 12 00:11:58 2013 +0200 summary: Issue #18408: ceval.c: in debug mode, convert the PyErr_Occurred() check on exception (when getting NULL) to an assertion to detect bugs earlier files: Python/ceval.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3026,9 +3026,13 @@ why = WHY_EXCEPTION; /* Double-check exception status. */ +#ifdef NDEBUG if (!PyErr_Occurred()) PyErr_SetString(PyExc_SystemError, "error return without exception set"); +#else + assert(PyErr_Occurred()); +#endif /* Log traceback info. */ PyTraceBack_Here(f); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 00:59:08 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 00:59:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_errors?= =?utf-8?q?=2Ec=3A_in_debug_mode=2C_calling_PyErr=5FBadInternalCall=28=29_?= =?utf-8?q?now?= Message-ID: <3brt4D45wPz7LkQ@mail.python.org> http://hg.python.org/cpython/rev/2f7c4df5cc46 changeset: 84574:2f7c4df5cc46 user: Victor Stinner date: Fri Jul 12 00:37:30 2013 +0200 summary: Issue #18408: errors.c: in debug mode, calling PyErr_BadInternalCall() now fails with an assertion error files: Python/errors.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -675,6 +675,7 @@ void PyErr_BadInternalCall(void) { + assert(0 && "bad argument to internal function"); PyErr_Format(PyExc_SystemError, "bad argument to internal function"); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 00:59:09 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 00:59:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_pmerge?= =?utf-8?q?=28=29_help_of_mro=5Fimplementation=28=29_now_raises_MemoryErro?= =?utf-8?q?r_on?= Message-ID: <3brt4F6ZgWz7LkJ@mail.python.org> http://hg.python.org/cpython/rev/affb87b1d7ec changeset: 84575:affb87b1d7ec user: Victor Stinner date: Fri Jul 12 00:42:14 2013 +0200 summary: Issue #18408: pmerge() help of mro_implementation() now raises MemoryError on memory allocation failure Replace also PyMem_Free() with PyMem_FREE() to be consistent with the rest of the function. files: Objects/typeobject.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1456,8 +1456,10 @@ that is not included in acc. */ remain = (int *)PyMem_MALLOC(SIZEOF_INT*to_merge_size); - if (remain == NULL) + if (remain == NULL) { + PyErr_NoMemory(); return -1; + } for (i = 0; i < to_merge_size; i++) remain[i] = 0; @@ -1489,7 +1491,7 @@ } ok = PyList_Append(acc, candidate); if (ok < 0) { - PyMem_Free(remain); + PyMem_FREE(remain); return -1; } for (j = 0; j < to_merge_size; j++) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 00:59:11 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 00:59:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_=5FPyMem?= =?utf-8?q?oTable=5FResizeTable=28=29_now_restores_the_old_table_if?= Message-ID: <3brt4H1c7gz7Lkc@mail.python.org> http://hg.python.org/cpython/rev/f85fcbbbe8de changeset: 84576:f85fcbbbe8de user: Victor Stinner date: Fri Jul 12 00:53:26 2013 +0200 summary: Issue #18408: _PyMemoTable_ResizeTable() now restores the old table if allocating a bigger table failed PyMemoTable destructor does crash if mt_table is NULL. files: Modules/_pickle.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -529,7 +529,7 @@ oldtable = self->mt_table; self->mt_table = PyMem_MALLOC(new_size * sizeof(PyMemoEntry)); if (self->mt_table == NULL) { - PyMem_FREE(oldtable); + self->mt_table = oldtable; PyErr_NoMemory(); return -1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 00:59:12 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 00:59:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_=5Fpickl?= =?utf-8?q?e=2Ec=3A_Add_missing_PyErr=5FNoMemory=28=29_on_memory_allocatio?= =?utf-8?q?n?= Message-ID: <3brt4J3sMVz7LkX@mail.python.org> http://hg.python.org/cpython/rev/bb5da6e795a1 changeset: 84577:bb5da6e795a1 user: Victor Stinner date: Fri Jul 12 00:53:57 2013 +0200 summary: Issue #18408: _pickle.c: Add missing PyErr_NoMemory() on memory allocation failures files: Modules/_pickle.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -436,6 +436,7 @@ new->mt_table = PyMem_MALLOC(self->mt_allocated * sizeof(PyMemoEntry)); if (new->mt_table == NULL) { PyMem_FREE(new); + PyErr_NoMemory(); return NULL; } for (i = 0; i < self->mt_allocated; i++) { @@ -1003,8 +1004,10 @@ char **result) { char *input_line = PyMem_Realloc(self->input_line, len + 1); - if (input_line == NULL) - return -1; + if (input_line == NULL) { + PyErr_NoMemory(); + return -1; + } memcpy(input_line, line, len); input_line[len] = '\0'; @@ -1101,8 +1104,10 @@ _Unpickler_NewMemo(Py_ssize_t new_size) { PyObject **memo = PyMem_MALLOC(new_size * sizeof(PyObject *)); - if (memo == NULL) + if (memo == NULL) { + PyErr_NoMemory(); return NULL; + } memset(memo, 0, new_size * sizeof(PyObject *)); return memo; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 01:42:53 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 01:42:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_pars?= =?utf-8?q?er=2Esequence2st=28=29_and_parser=2Etuple2st=28=29=3A_raise_Mem?= =?utf-8?q?oryError?= Message-ID: <3brv2j47KtzRBr@mail.python.org> http://hg.python.org/cpython/rev/89c6495d1ff2 changeset: 84578:89c6495d1ff2 user: Victor Stinner date: Fri Jul 12 01:33:59 2013 +0200 summary: Issue #18408: Fix parser.sequence2st() and parser.tuple2st(): raise MemoryError on memory allocation failure Instead of ignoring the memory allocation failure and create invalid objects. files: Modules/parsermodule.c | 19 +++++++++++++++---- 1 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c --- a/Modules/parsermodule.c +++ b/Modules/parsermodule.c @@ -809,8 +809,13 @@ return 0; } strn = (char *)PyObject_MALLOC(len + 1); - if (strn != NULL) - (void) memcpy(strn, temp_str, len + 1); + if (strn == NULL) { + Py_DECREF(temp); + Py_XDECREF(elem); + PyErr_NoMemory(); + return 0; + } + (void) memcpy(strn, temp_str, len + 1); Py_DECREF(temp); } else if (!ISNONTERMINAL(type)) { @@ -906,8 +911,14 @@ return NULL; } res->n_str = (char *)PyObject_MALLOC(len + 1); - if (res->n_str != NULL && temp != NULL) - (void) memcpy(res->n_str, temp, len + 1); + if (res->n_str == NULL) { + Py_DECREF(res); + Py_DECREF(encoding); + Py_DECREF(tuple); + PyErr_NoMemory(); + return NULL; + } + (void) memcpy(res->n_str, temp, len + 1); Py_DECREF(encoding); Py_DECREF(tuple); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 01:42:54 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 01:42:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_parser_m?= =?utf-8?q?odule=3A_fix_error_handling_in_node2tuple=28=29?= Message-ID: <3brv2k6KWLzS6Y@mail.python.org> http://hg.python.org/cpython/rev/c80a9705803a changeset: 84579:c80a9705803a user: Victor Stinner date: Fri Jul 12 01:35:10 2013 +0200 summary: Issue #18408: parser module: fix error handling in node2tuple() Handle PyLong_FromLong() and PyUnicode_FromString() failures files: Modules/parsermodule.c | 82 +++++++++++++++++++---------- 1 files changed, 53 insertions(+), 29 deletions(-) diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c --- a/Modules/parsermodule.c +++ b/Modules/parsermodule.c @@ -83,54 +83,78 @@ int lineno, /* include line numbers? */ int col_offset) /* include column offsets? */ { + PyObject *result = NULL, *w; + if (n == NULL) { Py_INCREF(Py_None); - return (Py_None); + return Py_None; } + if (ISNONTERMINAL(TYPE(n))) { int i; - PyObject *v; - PyObject *w; - - v = mkseq(1 + NCH(n) + (TYPE(n) == encoding_decl)); - if (v == NULL) - return (v); + + result = mkseq(1 + NCH(n) + (TYPE(n) == encoding_decl)); + if (result == NULL) + goto error; + w = PyLong_FromLong(TYPE(n)); - if (w == NULL) { - Py_DECREF(v); - return ((PyObject*) NULL); - } - (void) addelem(v, 0, w); + if (w == NULL) + goto error; + (void) addelem(result, 0, w); + for (i = 0; i < NCH(n); i++) { w = node2tuple(CHILD(n, i), mkseq, addelem, lineno, col_offset); - if (w == NULL) { - Py_DECREF(v); - return ((PyObject*) NULL); - } - (void) addelem(v, i+1, w); + if (w == NULL) + goto error; + (void) addelem(result, i+1, w); } - if (TYPE(n) == encoding_decl) - (void) addelem(v, i+1, PyUnicode_FromString(STR(n))); - return (v); + if (TYPE(n) == encoding_decl) { + w = PyUnicode_FromString(STR(n)); + if (w == NULL) + goto error; + (void) addelem(result, i+1, w); + } } else if (ISTERMINAL(TYPE(n))) { - PyObject *result = mkseq(2 + lineno + col_offset); - if (result != NULL) { - (void) addelem(result, 0, PyLong_FromLong(TYPE(n))); - (void) addelem(result, 1, PyUnicode_FromString(STR(n))); - if (lineno == 1) - (void) addelem(result, 2, PyLong_FromLong(n->n_lineno)); - if (col_offset == 1) - (void) addelem(result, 3, PyLong_FromLong(n->n_col_offset)); + result = mkseq(2 + lineno + col_offset); + if (result == NULL) + goto error; + + w = PyLong_FromLong(TYPE(n)); + if (w == NULL) + goto error; + (void) addelem(result, 0, w); + + w = PyUnicode_FromString(STR(n)); + if (w == NULL) + goto error; + (void) addelem(result, 1, w); + + if (lineno == 1) { + w = PyLong_FromLong(n->n_lineno); + if (w == NULL) + goto error; + (void) addelem(result, 2, w); } - return (result); + + if (col_offset == 1) { + w = PyLong_FromLong(n->n_col_offset); + if (w == NULL) + goto error; + (void) addelem(result, 3, w); + } } else { PyErr_SetString(PyExc_SystemError, "unrecognized parse tree node type"); return ((PyObject*) NULL); } + return result; + +error: + Py_XDECREF(result); + return NULL; } /* * End of material copyrighted by Stichting Mathematisch Centrum. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 02:07:51 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 02:07:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_crea?= =?utf-8?q?te=5Fextra=28=29_of_=5Felementtree=2Ec=2C_raise_MemoryError_on_?= =?utf-8?q?memory?= Message-ID: <3brvbW3d0YzSlp@mail.python.org> http://hg.python.org/cpython/rev/60b1d7967ef8 changeset: 84580:60b1d7967ef8 user: Victor Stinner date: Fri Jul 12 02:03:34 2013 +0200 summary: Issue #18408: Fix create_extra() of _elementtree.c, raise MemoryError on memory allocation failure files: Modules/_elementtree.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -170,8 +170,10 @@ create_extra(ElementObject* self, PyObject* attrib) { self->extra = PyObject_Malloc(sizeof(ElementObjectExtra)); - if (!self->extra) + if (!self->extra) { + PyErr_NoMemory(); return -1; + } if (!attrib) attrib = Py_None; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 02:07:52 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 12 Jul 2013 02:07:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_cons?= =?utf-8?q?tructors_of_=5Felementtree=2Ec?= Message-ID: <3brvbX5wmvz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/1e0afd558ba3 changeset: 84581:1e0afd558ba3 user: Victor Stinner date: Fri Jul 12 02:05:17 2013 +0200 summary: Issue #18408: Fix constructors of _elementtree.c * Use Py_DECREF() instead of PyObject_GC_Del() to release correctly all resources * Raise MemoryError on memory allocation failure files: Modules/_elementtree.c | 27 +++++++++++++++------------ 1 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -237,15 +237,16 @@ self->weakreflist = NULL; + ALLOC(sizeof(ElementObject), "create element"); + PyObject_GC_Track(self); + if (attrib != Py_None && !is_empty_dict(attrib)) { if (create_extra(self, attrib) < 0) { - PyObject_GC_Del(self); + Py_DECREF(self); return NULL; } } - ALLOC(sizeof(ElementObject), "create element"); - PyObject_GC_Track(self); return (PyObject*) self; } @@ -2122,14 +2123,6 @@ it = PyObject_GC_New(ElementIterObject, &ElementIter_Type); if (!it) return NULL; - if (!(it->parent_stack = PyObject_Malloc(sizeof(ParentLocator)))) { - PyObject_GC_Del(it); - return NULL; - } - - it->parent_stack->parent = NULL; - it->parent_stack->child_index = 0; - it->parent_stack->next = NULL; if (PyUnicode_Check(tag)) star = PyUnicode_FromString("*"); @@ -2147,8 +2140,18 @@ Py_INCREF(self); it->root_element = self; - PyObject_GC_Track(it); + + it->parent_stack = PyObject_Malloc(sizeof(ParentLocator)); + if (it->parent_stack == NULL) { + Py_DECREF(it); + PyErr_NoMemory(); + return NULL; + } + it->parent_stack->parent = NULL; + it->parent_stack->child_index = 0; + it->parent_stack->next = NULL; + return (PyObject *)it; } -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 12 05:49:04 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 12 Jul 2013 05:49:04 +0200 Subject: [Python-checkins] Daily reference leaks (1e0afd558ba3): sum=0 Message-ID: results for 1e0afd558ba3 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogB_3rgI', '-x'] From python-checkins at python.org Fri Jul 12 16:48:50 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 12 Jul 2013 16:48:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devinabox=3A_Issue_=2318362=3A_Allow_?= =?utf-8?q?for_build=5Fpython=2Epy_to_be_used_to_build_CPython_in?= Message-ID: <3bsH824LlHz7Lkg@mail.python.org> http://hg.python.org/devinabox/rev/fe1c35cbc9a0 changeset: 49:fe1c35cbc9a0 user: Brett Cannon date: Fri Jul 12 10:48:45 2013 -0400 summary: Issue #18362: Allow for build_python.py to be used to build CPython in other clones. files: build_cpython.py | 22 +++++++++++++++------- 1 files changed, 15 insertions(+), 7 deletions(-) diff --git a/build_cpython.py b/build_cpython.py --- a/build_cpython.py +++ b/build_cpython.py @@ -4,14 +4,15 @@ On all platforms, return the path to the executable. """ +from __future__ import print_function + import multiprocessing import os import subprocess import sys -def executable(): - directory = 'cpython' +def executable(directory): cmd = os.path.join(directory, 'python') # UNIX if not os.path.isfile(cmd): @@ -28,12 +29,11 @@ return os.path.abspath(cmd) -def main(): +def main(directory): if sys.platform == 'win32': print("See the devguide's Getting Set Up guide for building under " "Windows") - directory = 'cpython' cwd = os.getcwd() os.chdir(directory) try: @@ -46,9 +46,17 @@ subprocess.call(make_cmd) finally: os.chdir(cwd) - return executable() + return executable(directory) if __name__ == '__main__': - executable = main() - print(executable or 'No executable found') + arg_count = len(sys.argv) - 1 + if arg_count > 1: + raise ValueError( + '0 or 1 arguments expected, not {}'.format(arg_count)) + executable = main(sys.argv[1] if arg_count else 'cpython') + if not executable: + print('CPython executable NOT found') + else: + print('CPython executable can be found at:') + print(' ', executable) sys.exit(0 if executable else 1) -- Repository URL: http://hg.python.org/devinabox From python-checkins at python.org Fri Jul 12 16:51:02 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 12 Jul 2013 16:51:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devinabox=3A_Issue_=2318361=3A_Use_os?= =?utf-8?q?=2Ecpu=5Fcount=28=29_when_available=2E?= Message-ID: <3bsHBZ2GsLz7LkV@mail.python.org> http://hg.python.org/devinabox/rev/3446dee09265 changeset: 50:3446dee09265 user: Brett Cannon date: Fri Jul 12 10:50:57 2013 -0400 summary: Issue #18361: Use os.cpu_count() when available. files: build_cpython.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build_cpython.py b/build_cpython.py --- a/build_cpython.py +++ b/build_cpython.py @@ -6,11 +6,15 @@ """ from __future__ import print_function -import multiprocessing import os import subprocess import sys +try: + from os import cpu_count +except ImportError: + from multiprocessing import cpu_count + def executable(directory): cmd = os.path.join(directory, 'python') @@ -42,7 +46,7 @@ else: subprocess.check_call(['./configure', '--prefix=/tmp/cpython', '--with-pydebug']) - make_cmd = ['make', '-s', '-j', str(multiprocessing.cpu_count())] + make_cmd = ['make', '-s', '-j', str(cpu_count())] subprocess.call(make_cmd) finally: os.chdir(cwd) -- Repository URL: http://hg.python.org/devinabox From python-checkins at python.org Fri Jul 12 16:53:46 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 12 Jul 2013 16:53:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devinabox=3A_Issue_=2318363=3A_Use_ab?= =?utf-8?q?br_tag_over_acronym=2E?= Message-ID: <3bsHFk4VDSz7Lkc@mail.python.org> http://hg.python.org/devinabox/rev/fae104051a63 changeset: 51:fae104051a63 user: Brett Cannon date: Fri Jul 12 10:53:41 2013 -0400 summary: Issue #18363: Use abbr tag over acronym. files: index.html | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -30,7 +30,8 @@
  • Test coverage report (in regards to increasing test coverage) -
  • PEPs +
  • + PEPs (only read if necessary) @@ -40,4 +41,4 @@ (find the CPython binary & build if possible)
  • full_coverage.py (build, run, and/or report for coverage.py; see help message for usage) - \ No newline at end of file + -- Repository URL: http://hg.python.org/devinabox From python-checkins at python.org Fri Jul 12 17:04:33 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 12 Jul 2013 17:04:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318415=3A_Normaliz?= =?utf-8?q?e_what_type_of_quotes_are_used_with_string?= Message-ID: <3bsHV90b5bz7Lkf@mail.python.org> http://hg.python.org/cpython/rev/33d379c2bb79 changeset: 84582:33d379c2bb79 user: Brett Cannon date: Fri Jul 12 11:04:23 2013 -0400 summary: Issue #18415: Normalize what type of quotes are used with string constants in importlib._bootstrap. Along the way clean up from string interpolation to use the repr explicitly. Initial patch by Madison May. files: Lib/importlib/_bootstrap.py | 60 ++++++++++++------------ Python/importlib.h | 12 ++-- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -175,7 +175,7 @@ self.count += 1 return True if self.has_deadlock(): - raise _DeadlockError("deadlock detected by %r" % self) + raise _DeadlockError('deadlock detected by %r' % self) if self.wakeup.acquire(False): self.waiters += 1 # Wait for a release() call @@ -188,7 +188,7 @@ tid = _thread.get_ident() with self.lock: if self.owner != tid: - raise RuntimeError("cannot release un-acquired lock") + raise RuntimeError('cannot release un-acquired lock') assert self.count > 0 self.count -= 1 if self.count == 0: @@ -198,7 +198,7 @@ self.wakeup.release() def __repr__(self): - return "_ModuleLock({!r}) at {}".format(self.name, id(self)) + return '_ModuleLock({!r}) at {}'.format(self.name, id(self)) class _DummyModuleLock: @@ -215,11 +215,11 @@ def release(self): if self.count == 0: - raise RuntimeError("cannot release un-acquired lock") + raise RuntimeError('cannot release un-acquired lock') self.count -= 1 def __repr__(self): - return "_DummyModuleLock({!r}) at {}".format(self.name, id(self)) + return '_DummyModuleLock({!r}) at {}'.format(self.name, id(self)) # The following two functions are for consumption by Python/import.c. @@ -603,7 +603,7 @@ if name is None: name = self.name elif self.name != name: - raise ImportError("loader cannot handle %s" % name, name=name) + raise ImportError('loader cannot handle %s' % name, name=name) return method(self, name, *args, **kwargs) _wrap(_check_name_wrapper, method) return _check_name_wrapper @@ -613,7 +613,7 @@ """Decorator to verify the named module is built-in.""" def _requires_builtin_wrapper(self, fullname): if fullname not in sys.builtin_module_names: - raise ImportError("{} is not a built-in module".format(fullname), + raise ImportError('{} is not a built-in module'.format(fullname), name=fullname) return fxn(self, fullname) _wrap(_requires_builtin_wrapper, fxn) @@ -624,7 +624,7 @@ """Decorator to verify the named module is frozen.""" def _requires_frozen_wrapper(self, fullname): if not _imp.is_frozen(fullname): - raise ImportError("{} is not a frozen module".format(fullname), + raise ImportError('{} is not a frozen module'.format(fullname), name=fullname) return fxn(self, fullname) _wrap(_requires_frozen_wrapper, fxn) @@ -639,7 +639,7 @@ # return None. loader, portions = self.find_loader(fullname) if loader is None and len(portions): - msg = "Not importing directory {}: missing __init__" + msg = 'Not importing directory {}: missing __init__' _warnings.warn(msg.format(portions[0]), ImportWarning) return loader @@ -694,7 +694,7 @@ pass else: if _r_long(raw_size) != source_size: - raise ImportError("bytecode is stale for {!r}".format(name), + raise ImportError('bytecode is stale for {!r}'.format(name), **exc_details) return data[12:] @@ -708,7 +708,7 @@ _imp._fix_co_filename(code, source_path) return code else: - raise ImportError("Non-code object in {!r}".format(bytecode_path), + raise ImportError('Non-code object in {!r}'.format(bytecode_path), name=name, path=bytecode_path) def _code_to_bytecode(code, mtime=0, source_size=0): @@ -746,7 +746,7 @@ @classmethod def module_repr(cls, module): - return "".format(module.__name__) + return ''.format(module.__name__) @classmethod def find_module(cls, fullname, path=None): @@ -798,7 +798,7 @@ @classmethod def module_repr(cls, m): - return "".format(m.__name__) + return ''.format(m.__name__) @classmethod def find_module(cls, fullname, path=None): @@ -842,11 +842,11 @@ """ REGISTRY_KEY = ( - "Software\\Python\\PythonCore\\{sys_version}" - "\\Modules\\{fullname}") + 'Software\\Python\\PythonCore\\{sys_version}' + '\\Modules\\{fullname}') REGISTRY_KEY_DEBUG = ( - "Software\\Python\\PythonCore\\{sys_version}" - "\\Modules\\{fullname}\\Debug") + 'Software\\Python\\PythonCore\\{sys_version}' + '\\Modules\\{fullname}\\Debug') DEBUG_BUILD = False # Changed in _setup() @classmethod @@ -866,7 +866,7 @@ sys_version=sys.version[:3]) try: with cls._open_registry(key) as hkey: - filepath = _winreg.QueryValue(hkey, "") + filepath = _winreg.QueryValue(hkey, '') except OSError: return None return filepath @@ -973,7 +973,7 @@ try: source_bytes = self.get_data(path) except OSError as exc: - raise ImportError("source not available through get_data()", + raise ImportError('source not available through get_data()', name=fullname) from exc return decode_source(source_bytes) @@ -1218,7 +1218,7 @@ return len(self._recalculate()) def __repr__(self): - return "_NamespacePath({!r})".format(self._path) + return '_NamespacePath({!r})'.format(self._path) def __contains__(self, item): return item in self._recalculate() @@ -1233,7 +1233,7 @@ @classmethod def module_repr(cls, module): - return "".format(module.__name__) + return ''.format(module.__name__) def is_package(self, fullname): return True @@ -1467,13 +1467,13 @@ def path_hook_for_FileFinder(path): """Path hook for importlib.machinery.FileFinder.""" if not _path_isdir(path): - raise ImportError("only directories are supported", path=path) + raise ImportError('only directories are supported', path=path) return cls(path, *loader_details) return path_hook_for_FileFinder def __repr__(self): - return "FileFinder({!r})".format(self.path) + return 'FileFinder({!r})'.format(self.path) # Import itself ############################################################### @@ -1520,18 +1520,18 @@ def _sanity_check(name, package, level): """Verify arguments are "sane".""" if not isinstance(name, str): - raise TypeError("module name must be str, not {}".format(type(name))) + raise TypeError('module name must be str, not {}'.format(type(name))) if level < 0: raise ValueError('level must be >= 0') if package: if not isinstance(package, str): - raise TypeError("__package__ not set to a string") + raise TypeError('__package__ not set to a string') elif package not in sys.modules: - msg = ("Parent module {!r} not loaded, cannot perform relative " - "import") + msg = ('Parent module {!r} not loaded, cannot perform relative ' + 'import') raise SystemError(msg.format(package)) if not name and level == 0: - raise ValueError("Empty module name") + raise ValueError('Empty module name') _ERR_MSG_PREFIX = 'No module named ' @@ -1614,8 +1614,8 @@ module = sys.modules[name] if module is None: _imp.release_lock() - message = ("import of {} halted; " - "None in sys.modules".format(name)) + message = ('import of {} halted; ' + 'None in sys.modules'.format(name)) raise ImportError(message, name=name) _lock_unlock_module(name) return module 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 Jul 12 17:08:25 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 12 Jul 2013 17:08:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devinabox=3A_Issue_=2318388=3A_Link_t?= =?utf-8?q?o_the_contributor_agreement=2E?= Message-ID: <3bsHZd2h8Lz7Lk4@mail.python.org> http://hg.python.org/devinabox/rev/28294583a9c9 changeset: 52:28294583a9c9 user: Brett Cannon date: Fri Jul 12 11:08:19 2013 -0400 summary: Issue #18388: Link to the contributor agreement. files: index.html | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -16,16 +16,13 @@ a { font-size: x-large; } - - .note { - font-size: small; - }

    Documentation

    • Devguide (read first) +
    • Python Contributor Agreement Form (cannot commit your contributions until you sign this)
    • Python documentation
    • Test coverage report (in regards to -- Repository URL: http://hg.python.org/devinabox From python-checkins at python.org Fri Jul 12 17:22:37 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 12 Jul 2013 17:22:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318342=3A_Use_the_?= =?utf-8?q?repr_of_a_module_name_for_=60=60from_=2E=2E=2E_import?= Message-ID: <3bsHv165cCz7Ll7@mail.python.org> http://hg.python.org/cpython/rev/c3f9292c8efe changeset: 84583:c3f9292c8efe user: Brett Cannon date: Fri Jul 12 11:22:26 2013 -0400 summary: Issue #18342: Use the repr of a module name for ``from ... import ...`` when an ImportError occurs. Other cases had already been switched over to using the repr. Thanks to Tomasz Ma?kowiak for the patch. files: Lib/test/test_import.py | 8 ++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ Python/ceval.c | 2 +- 4 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -321,6 +321,14 @@ stdout, stderr = popen.communicate() self.assertIn(b"ImportError", stdout) + def test_from_import_message_for_nonexistent_module(self): + with self.assertRaisesRegexp(ImportError, "^No module named 'bogus'"): + from bogus import foo + + def test_from_import_message_for_existing_module(self): + with self.assertRaisesRegexp(ImportError, "^cannot import name 'bogus'"): + from re import bogus + @skip_if_dont_write_bytecode class FilePermissionTests(unittest.TestCase): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -786,6 +786,7 @@ Tim MacKenzie Nick Maclaren Don MacMillen +Tomasz Ma?kowiak Steve Majewski Grzegorz Makarewicz David Malcolm diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18342: Use the repr of a module name when an import fails when using + ``from ... import ...``. + - Issue #17872: Fix a segfault in marshal.load() when input stream returns more bytes than requested. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4602,7 +4602,7 @@ x = PyObject_GetAttr(v, name); if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Format(PyExc_ImportError, "cannot import name %S", name); + PyErr_Format(PyExc_ImportError, "cannot import name %R", name); } return x; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 17:30:41 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 12 Jul 2013 17:30:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317845=3A_Clarify_?= =?utf-8?q?the_message_setup=2Epy_prints_upon_successfully?= Message-ID: <3bsJ4K5YrHz7LkX@mail.python.org> http://hg.python.org/cpython/rev/e13ff9fdfaf9 changeset: 84584:e13ff9fdfaf9 user: Brett Cannon date: Fri Jul 12 11:30:32 2013 -0400 summary: Issue #17845: Clarify the message setup.py prints upon successfully building Python but having some optional module which didn't build. Patch by Yogesh Chaudhari. files: Misc/NEWS | 2 ++ setup.py | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -631,6 +631,8 @@ Build ----- +- Issue #17845: Clarified the message printed when some module are not built. + - Issue #18256: Compilation fix for recent AIX releases. Patch by David Edelsohn. diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -259,8 +259,9 @@ if missing: print() - print("Python build finished, but the necessary bits to build " - "these modules were not found:") + print("Python build finished successfully!") + print("The necessary bits to build these optional modules were not " + "found:") print_three_column(missing) print("To find the necessary bits, look in setup.py in" " detect_modules() for the module's name.") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 17:53:41 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 12 Jul 2013 17:53:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Issue_=2318390=3A_Add_a_l?= =?utf-8?q?ittle_comment_on_how_to_do_a_proper_file?= Message-ID: <3bsJZs1LLDz7Lll@mail.python.org> http://hg.python.org/devguide/rev/15249b189347 changeset: 624:15249b189347 user: Brett Cannon date: Fri Jul 12 11:53:34 2013 -0400 summary: Issue #18390: Add a little comment on how to do a proper file revert after a merge. files: committing.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/committing.rst b/committing.rst --- a/committing.rst +++ b/committing.rst @@ -385,7 +385,7 @@ cd ../3.4 hg merge 3.3 - # Fix any conflicts; compile; run the test suite + # Fix any conflicts (e.g. ``hg revert -r default Misc/NEWS``); compile; run the test suite hg ci -m '#12345: merge with 3.3.' If you are not using the share extension, you will need to use -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jul 12 21:58:29 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 21:58:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDM0?= =?utf-8?q?=3A_Updated_example_script_in_venv_docs_to_use_setuptools_rathe?= =?utf-8?q?r_than?= Message-ID: <3bsQ1K1gSqzPX7@mail.python.org> http://hg.python.org/cpython/rev/1641a03dbe7b changeset: 84585:1641a03dbe7b branch: 3.3 parent: 84558:4acb822f4c43 user: Vinay Sajip date: Fri Jul 12 20:54:25 2013 +0100 summary: Issue #18434: Updated example script in venv docs to use setuptools rather than Distribute. files: Doc/library/venv.rst | 49 ++++++++++++++++++------------- 1 files changed, 28 insertions(+), 21 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -187,7 +187,7 @@ -------------------------------------- The following script shows how to extend :class:`EnvBuilder` by implementing a -subclass which installs Distribute and pip into a created venv:: +subclass which installs setuptools and pip into a created venv:: import os import os.path @@ -198,16 +198,16 @@ from urllib.request import urlretrieve import venv - class DistributeEnvBuilder(venv.EnvBuilder): + class ExtendedEnvBuilder(venv.EnvBuilder): """ - This builder installs Distribute and pip so that you can pip or + This builder installs setuptools and pip so that you can pip or easy_install other packages into the created environment. - :param nodist: If True, Distribute is not installed into the created - environment. + :param nodist: If True, setuptools and pip are not installed into the + created environment. :param nopip: If True, pip is not installed into the created environment. - :param progress: If Distribute or pip are installed, the progress of the + :param progress: If setuptools or pip are installed, the progress of the installation can be monitored by passing a progress callable. If specified, it is called with two arguments: a string indicating some progress, and a @@ -237,9 +237,11 @@ :param context: The information for the environment creation request being processed. """ + os.environ['VIRTUAL_ENV'] = context.env_dir if not self.nodist: - self.install_distribute(context) - if not self.nopip: + self.install_setuptools(context) + # Can't install pip without setuptools + if not self.nopip and not self.nodist: self.install_pip(context) def reader(self, stream, context): @@ -269,10 +271,14 @@ # Download script into the env's binaries folder urlretrieve(url, distpath) progress = self.progress + if self.verbose: + term = '\n' + else: + term = '' if progress is not None: - progress('Installing %s' %name, 'main') + progress('Installing %s ...%s' % (name, term), 'main') else: - sys.stderr.write('Installing %s ' % name) + sys.stderr.write('Installing %s ...%s' % (name, term)) sys.stderr.flush() # Install in the env args = [context.env_exe, fn] @@ -291,17 +297,17 @@ # Clean up - no longer needed os.unlink(distpath) - def install_distribute(self, context): + def install_setuptools(self, context): """ - Install Distribute in the environment. + Install setuptools in the environment. :param context: The information for the environment creation request being processed. """ - url = 'http://python-distribute.org/distribute_setup.py' - self.install_script(context, 'distribute', url) - # clear up the distribute archive which gets downloaded - pred = lambda o: o.startswith('distribute-') and o.endswith('.tar.gz') + url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py' + self.install_script(context, 'setuptools', url) + # clear up the setuptools archive which gets downloaded + pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz') files = filter(pred, os.listdir(context.bin_path)) for f in files: f = os.path.join(context.bin_path, f) @@ -336,10 +342,10 @@ 'directories.') parser.add_argument('dirs', metavar='ENV_DIR', nargs='+', help='A directory to create the environment in.') - parser.add_argument('--no-distribute', default=False, + parser.add_argument('--no-setuptools', default=False, action='store_true', dest='nodist', - help="Don't install Distribute in the virtual " - "environment.") + help="Don't install setuptools or pip in the " + "virtual environment.") parser.add_argument('--no-pip', default=False, action='store_true', dest='nopip', help="Don't install pip in the virtual " @@ -370,11 +376,11 @@ parser.add_argument('--verbose', default=False, action='store_true', dest='verbose', help='Display the output ' 'from the scripts which ' - 'install Distribute and pip.') + 'install setuptools and pip.') options = parser.parse_args(args) if options.upgrade and options.clear: raise ValueError('you cannot supply --upgrade and --clear together.') - builder = DistributeEnvBuilder(system_site_packages=options.system_site, + builder = ExtendedEnvBuilder(system_site_packages=options.system_site, clear=options.clear, symlinks=options.symlinks, upgrade=options.upgrade, @@ -393,5 +399,6 @@ print('Error: %s' % e, file=sys.stderr) sys.exit(rc) + This script is also available for download `online `_. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 21:58:30 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 21:58:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2318434=3A_Merged_documentation_update_from_3=2E?= =?utf-8?q?3=2E?= Message-ID: <3bsQ1L5zgzz7Lkp@mail.python.org> http://hg.python.org/cpython/rev/24a55f04a571 changeset: 84586:24a55f04a571 parent: 84584:e13ff9fdfaf9 parent: 84585:1641a03dbe7b user: Vinay Sajip date: Fri Jul 12 20:58:14 2013 +0100 summary: Closes #18434: Merged documentation update from 3.3. files: Doc/library/venv.rst | 49 ++++++++++++++++++------------- 1 files changed, 28 insertions(+), 21 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -186,7 +186,7 @@ -------------------------------------- The following script shows how to extend :class:`EnvBuilder` by implementing a -subclass which installs Distribute and pip into a created venv:: +subclass which installs setuptools and pip into a created venv:: import os import os.path @@ -197,16 +197,16 @@ from urllib.request import urlretrieve import venv - class DistributeEnvBuilder(venv.EnvBuilder): + class ExtendedEnvBuilder(venv.EnvBuilder): """ - This builder installs Distribute and pip so that you can pip or + This builder installs setuptools and pip so that you can pip or easy_install other packages into the created environment. - :param nodist: If True, Distribute is not installed into the created - environment. + :param nodist: If True, setuptools and pip are not installed into the + created environment. :param nopip: If True, pip is not installed into the created environment. - :param progress: If Distribute or pip are installed, the progress of the + :param progress: If setuptools or pip are installed, the progress of the installation can be monitored by passing a progress callable. If specified, it is called with two arguments: a string indicating some progress, and a @@ -236,9 +236,11 @@ :param context: The information for the environment creation request being processed. """ + os.environ['VIRTUAL_ENV'] = context.env_dir if not self.nodist: - self.install_distribute(context) - if not self.nopip: + self.install_setuptools(context) + # Can't install pip without setuptools + if not self.nopip and not self.nodist: self.install_pip(context) def reader(self, stream, context): @@ -268,10 +270,14 @@ # Download script into the env's binaries folder urlretrieve(url, distpath) progress = self.progress + if self.verbose: + term = '\n' + else: + term = '' if progress is not None: - progress('Installing %s' %name, 'main') + progress('Installing %s ...%s' % (name, term), 'main') else: - sys.stderr.write('Installing %s ' % name) + sys.stderr.write('Installing %s ...%s' % (name, term)) sys.stderr.flush() # Install in the env args = [context.env_exe, fn] @@ -290,17 +296,17 @@ # Clean up - no longer needed os.unlink(distpath) - def install_distribute(self, context): + def install_setuptools(self, context): """ - Install Distribute in the environment. + Install setuptools in the environment. :param context: The information for the environment creation request being processed. """ - url = 'http://python-distribute.org/distribute_setup.py' - self.install_script(context, 'distribute', url) - # clear up the distribute archive which gets downloaded - pred = lambda o: o.startswith('distribute-') and o.endswith('.tar.gz') + url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py' + self.install_script(context, 'setuptools', url) + # clear up the setuptools archive which gets downloaded + pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz') files = filter(pred, os.listdir(context.bin_path)) for f in files: f = os.path.join(context.bin_path, f) @@ -335,10 +341,10 @@ 'directories.') parser.add_argument('dirs', metavar='ENV_DIR', nargs='+', help='A directory to create the environment in.') - parser.add_argument('--no-distribute', default=False, + parser.add_argument('--no-setuptools', default=False, action='store_true', dest='nodist', - help="Don't install Distribute in the virtual " - "environment.") + help="Don't install setuptools or pip in the " + "virtual environment.") parser.add_argument('--no-pip', default=False, action='store_true', dest='nopip', help="Don't install pip in the virtual " @@ -369,11 +375,11 @@ parser.add_argument('--verbose', default=False, action='store_true', dest='verbose', help='Display the output ' 'from the scripts which ' - 'install Distribute and pip.') + 'install setuptools and pip.') options = parser.parse_args(args) if options.upgrade and options.clear: raise ValueError('you cannot supply --upgrade and --clear together.') - builder = DistributeEnvBuilder(system_site_packages=options.system_site, + builder = ExtendedEnvBuilder(system_site_packages=options.system_site, clear=options.clear, symlinks=options.symlinks, upgrade=options.upgrade, @@ -392,5 +398,6 @@ print('Error: %s' % e, file=sys.stderr) sys.exit(rc) + This script is also available for download `online `_. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:05:19 2013 From: python-checkins at python.org (r.david.murray) Date: Fri, 12 Jul 2013 22:05:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4NDMxOiBEZWNv?= =?utf-8?q?de_encoded_words_in_atoms_in_new_email_parser=2E?= Message-ID: <3bsQ9C2DjXz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/1f3c57ac07ed changeset: 84587:1f3c57ac07ed branch: 3.3 parent: 84558:4acb822f4c43 user: R David Murray date: Fri Jul 12 16:00:28 2013 -0400 summary: #18431: Decode encoded words in atoms in new email parser. There is more to be done here in terms of accepting RFC invalid input that some mailers accept, but this covers the valid RFC places where encoded words can occur in structured headers. files: Lib/email/_header_value_parser.py | 23 ++++++++- Lib/test/test_email/test__header_value_parser.py | 26 +++++++++- Lib/test/test_email/test_headerregistry.py | 24 +++++++++ Misc/NEWS | 3 + 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -1627,6 +1627,7 @@ def get_atom(value): """atom = [CFWS] 1*atext [CFWS] + An atom could be an rfc2047 encoded word. """ atom = Atom() if value and value[0] in CFWS_LEADER: @@ -1635,7 +1636,15 @@ if value and value[0] in ATOM_ENDS: raise errors.HeaderParseError( "expected atom but found '{}'".format(value)) - token, value = get_atext(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_atext(value) + else: + token, value = get_atext(value) atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) @@ -1664,12 +1673,22 @@ def get_dot_atom(value): """ dot-atom = [CFWS] dot-atom-text [CFWS] + Any place we can have a dot atom, we could instead have an rfc2047 encoded + word. """ dot_atom = DotAtom() if value[0] in CFWS_LEADER: token, value = get_cfws(value) dot_atom.append(token) - token, value = get_dot_atom_text(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_dot_atom_text(value) + else: + token, value = get_dot_atom_text(value) dot_atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -808,9 +808,13 @@ self.assertEqual(atom[2].comments, ['bar']) def test_get_atom_atom_ends_at_noncfws(self): - atom = self._test_get_x(parser.get_atom, + self._test_get_x(parser.get_atom, 'bob fred', 'bob ', 'bob ', [], 'fred') + def test_get_atom_rfc2047_atom(self): + self._test_get_x(parser.get_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_dot_atom_text def test_get_dot_atom_text(self): @@ -885,6 +889,10 @@ with self.assertRaises(errors.HeaderParseError): parser.get_dot_atom(' (foo) bar.bang. foo') + def test_get_dot_atom_rfc2047_atom(self): + self._test_get_x(parser.get_dot_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_word (if this were black box we'd repeat all the qs/atom tests) def test_get_word_atom_yields_atom(self): @@ -2156,6 +2164,22 @@ self.assertEqual(address[0].token_type, 'mailbox') + def test_get_address_rfc2047_display_name(self): + address = self._test_get_x(parser.get_address, + '=?utf-8?q?=C3=89ric?= ', + '?ric ', + '?ric ', + [], + '') + self.assertEqual(address.token_type, 'address') + self.assertEqual(len(address.mailboxes), 1) + self.assertEqual(address.mailboxes, + address.all_mailboxes) + self.assertEqual(address.mailboxes[0].display_name, + '?ric') + self.assertEqual(address[0].token_type, + 'mailbox') + def test_get_address_empty_group(self): address = self._test_get_x(parser.get_address, 'Monty Python:;', diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -158,6 +158,10 @@ '=?utf-8?q?=C3=89ric?=', '?ric'), + 'rfc2047_quopri_with_regular_text': ( + 'The =?utf-8?q?=C3=89ric=2C?= Himself', + 'The ?ric, Himself'), + } @@ -1119,6 +1123,26 @@ 'example.com', None), + 'rfc2047_atom_is_decoded': + ('=?utf-8?q?=C3=89ric?= ', + [], + '?ric ', + '?ric', + 'foo at example.com', + 'foo', + 'example.com', + None), + + 'rfc2047_atom_in_phrase_is_decoded': + ('The =?utf-8?q?=C3=89ric=2C?= Himself ', + [], + '"The ?ric, Himself" ', + 'The ?ric, Himself', + 'foo at example.com', + 'foo', + 'example.com', + None), + } # XXX: Need many more examples, and in particular some with names in diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,9 @@ Library ------- +- Issue #18431: The new email header parser now decodes RFC2047 encoded words + in structured headers. + - Issue #18044: The new email header parser was mis-parsing encoded words where an encoded character immediately followed the '?' that follows the CTE character, resulting in a decoding failure. They are now decoded correctly. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:05:20 2013 From: python-checkins at python.org (r.david.murray) Date: Fri, 12 Jul 2013 22:05:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_=2318431=3A_Decode_encoded_words_in_atoms_in_ne?= =?utf-8?q?w_email_parser=2E?= Message-ID: <3bsQ9D5Qrcz7Lkp@mail.python.org> http://hg.python.org/cpython/rev/0c161b360ffe changeset: 84588:0c161b360ffe parent: 84584:e13ff9fdfaf9 parent: 84587:1f3c57ac07ed user: R David Murray date: Fri Jul 12 16:01:10 2013 -0400 summary: Merge: #18431: Decode encoded words in atoms in new email parser. files: Lib/email/_header_value_parser.py | 23 ++++++++- Lib/test/test_email/test__header_value_parser.py | 26 +++++++++- Lib/test/test_email/test_headerregistry.py | 24 +++++++++ Misc/NEWS | 3 + 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -1624,6 +1624,7 @@ def get_atom(value): """atom = [CFWS] 1*atext [CFWS] + An atom could be an rfc2047 encoded word. """ atom = Atom() if value and value[0] in CFWS_LEADER: @@ -1632,7 +1633,15 @@ if value and value[0] in ATOM_ENDS: raise errors.HeaderParseError( "expected atom but found '{}'".format(value)) - token, value = get_atext(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_atext(value) + else: + token, value = get_atext(value) atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) @@ -1661,12 +1670,22 @@ def get_dot_atom(value): """ dot-atom = [CFWS] dot-atom-text [CFWS] + Any place we can have a dot atom, we could instead have an rfc2047 encoded + word. """ dot_atom = DotAtom() if value[0] in CFWS_LEADER: token, value = get_cfws(value) dot_atom.append(token) - token, value = get_dot_atom_text(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_dot_atom_text(value) + else: + token, value = get_dot_atom_text(value) dot_atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -808,9 +808,13 @@ self.assertEqual(atom[2].comments, ['bar']) def test_get_atom_atom_ends_at_noncfws(self): - atom = self._test_get_x(parser.get_atom, + self._test_get_x(parser.get_atom, 'bob fred', 'bob ', 'bob ', [], 'fred') + def test_get_atom_rfc2047_atom(self): + self._test_get_x(parser.get_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_dot_atom_text def test_get_dot_atom_text(self): @@ -885,6 +889,10 @@ with self.assertRaises(errors.HeaderParseError): parser.get_dot_atom(' (foo) bar.bang. foo') + def test_get_dot_atom_rfc2047_atom(self): + self._test_get_x(parser.get_dot_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_word (if this were black box we'd repeat all the qs/atom tests) def test_get_word_atom_yields_atom(self): @@ -2156,6 +2164,22 @@ self.assertEqual(address[0].token_type, 'mailbox') + def test_get_address_rfc2047_display_name(self): + address = self._test_get_x(parser.get_address, + '=?utf-8?q?=C3=89ric?= ', + '?ric ', + '?ric ', + [], + '') + self.assertEqual(address.token_type, 'address') + self.assertEqual(len(address.mailboxes), 1) + self.assertEqual(address.mailboxes, + address.all_mailboxes) + self.assertEqual(address.mailboxes[0].display_name, + '?ric') + self.assertEqual(address[0].token_type, + 'mailbox') + def test_get_address_empty_group(self): address = self._test_get_x(parser.get_address, 'Monty Python:;', diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -158,6 +158,10 @@ '=?utf-8?q?=C3=89ric?=', '?ric'), + 'rfc2047_quopri_with_regular_text': ( + 'The =?utf-8?q?=C3=89ric=2C?= Himself', + 'The ?ric, Himself'), + } @@ -1119,6 +1123,26 @@ 'example.com', None), + 'rfc2047_atom_is_decoded': + ('=?utf-8?q?=C3=89ric?= ', + [], + '?ric ', + '?ric', + 'foo at example.com', + 'foo', + 'example.com', + None), + + 'rfc2047_atom_in_phrase_is_decoded': + ('The =?utf-8?q?=C3=89ric=2C?= Himself ', + [], + '"The ?ric, Himself" ', + 'The ?ric, Himself', + 'foo at example.com', + 'foo', + 'example.com', + None), + } # XXX: Need many more examples, and in particular some with names in diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -154,6 +154,9 @@ Library ------- +- Issue #18431: The new email header parser now decodes RFC2047 encoded words + in structured headers. + - Issue #18044: The new email header parser was mis-parsing encoded words where an encoded character immediately followed the '?' that follows the CTE character, resulting in a decoding failure. They are now decoded correctly. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:05:22 2013 From: python-checkins at python.org (r.david.murray) Date: Fri, 12 Jul 2013 22:05:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_Merge_heads=2E?= Message-ID: <3bsQ9G1r1Gz7LlJ@mail.python.org> http://hg.python.org/cpython/rev/d30e9bbabc09 changeset: 84589:d30e9bbabc09 branch: 3.3 parent: 84585:1641a03dbe7b parent: 84587:1f3c57ac07ed user: R David Murray date: Fri Jul 12 16:03:44 2013 -0400 summary: Merge heads. files: Lib/email/_header_value_parser.py | 23 ++++++++- Lib/test/test_email/test__header_value_parser.py | 26 +++++++++- Lib/test/test_email/test_headerregistry.py | 24 +++++++++ Misc/NEWS | 3 + 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -1627,6 +1627,7 @@ def get_atom(value): """atom = [CFWS] 1*atext [CFWS] + An atom could be an rfc2047 encoded word. """ atom = Atom() if value and value[0] in CFWS_LEADER: @@ -1635,7 +1636,15 @@ if value and value[0] in ATOM_ENDS: raise errors.HeaderParseError( "expected atom but found '{}'".format(value)) - token, value = get_atext(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_atext(value) + else: + token, value = get_atext(value) atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) @@ -1664,12 +1673,22 @@ def get_dot_atom(value): """ dot-atom = [CFWS] dot-atom-text [CFWS] + Any place we can have a dot atom, we could instead have an rfc2047 encoded + word. """ dot_atom = DotAtom() if value[0] in CFWS_LEADER: token, value = get_cfws(value) dot_atom.append(token) - token, value = get_dot_atom_text(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_dot_atom_text(value) + else: + token, value = get_dot_atom_text(value) dot_atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -808,9 +808,13 @@ self.assertEqual(atom[2].comments, ['bar']) def test_get_atom_atom_ends_at_noncfws(self): - atom = self._test_get_x(parser.get_atom, + self._test_get_x(parser.get_atom, 'bob fred', 'bob ', 'bob ', [], 'fred') + def test_get_atom_rfc2047_atom(self): + self._test_get_x(parser.get_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_dot_atom_text def test_get_dot_atom_text(self): @@ -885,6 +889,10 @@ with self.assertRaises(errors.HeaderParseError): parser.get_dot_atom(' (foo) bar.bang. foo') + def test_get_dot_atom_rfc2047_atom(self): + self._test_get_x(parser.get_dot_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_word (if this were black box we'd repeat all the qs/atom tests) def test_get_word_atom_yields_atom(self): @@ -2156,6 +2164,22 @@ self.assertEqual(address[0].token_type, 'mailbox') + def test_get_address_rfc2047_display_name(self): + address = self._test_get_x(parser.get_address, + '=?utf-8?q?=C3=89ric?= ', + '?ric ', + '?ric ', + [], + '') + self.assertEqual(address.token_type, 'address') + self.assertEqual(len(address.mailboxes), 1) + self.assertEqual(address.mailboxes, + address.all_mailboxes) + self.assertEqual(address.mailboxes[0].display_name, + '?ric') + self.assertEqual(address[0].token_type, + 'mailbox') + def test_get_address_empty_group(self): address = self._test_get_x(parser.get_address, 'Monty Python:;', diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -158,6 +158,10 @@ '=?utf-8?q?=C3=89ric?=', '?ric'), + 'rfc2047_quopri_with_regular_text': ( + 'The =?utf-8?q?=C3=89ric=2C?= Himself', + 'The ?ric, Himself'), + } @@ -1119,6 +1123,26 @@ 'example.com', None), + 'rfc2047_atom_is_decoded': + ('=?utf-8?q?=C3=89ric?= ', + [], + '?ric ', + '?ric', + 'foo at example.com', + 'foo', + 'example.com', + None), + + 'rfc2047_atom_in_phrase_is_decoded': + ('The =?utf-8?q?=C3=89ric=2C?= Himself ', + [], + '"The ?ric, Himself" ', + 'The ?ric, Himself', + 'foo at example.com', + 'foo', + 'example.com', + None), + } # XXX: Need many more examples, and in particular some with names in diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,9 @@ Library ------- +- Issue #18431: The new email header parser now decodes RFC2047 encoded words + in structured headers. + - Issue #18044: The new email header parser was mis-parsing encoded words where an encoded character immediately followed the '?' that follows the CTE character, resulting in a decoding failure. They are now decoded correctly. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:05:23 2013 From: python-checkins at python.org (r.david.murray) Date: Fri, 12 Jul 2013 22:05:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgaGVhZHMu?= Message-ID: <3bsQ9H56Dtz7Ll5@mail.python.org> http://hg.python.org/cpython/rev/693aec04f9cd changeset: 84590:693aec04f9cd parent: 84586:24a55f04a571 parent: 84588:0c161b360ffe user: R David Murray date: Fri Jul 12 16:04:18 2013 -0400 summary: Merge heads. files: Lib/email/_header_value_parser.py | 23 ++++++++- Lib/test/test_email/test__header_value_parser.py | 26 +++++++++- Lib/test/test_email/test_headerregistry.py | 24 +++++++++ Misc/NEWS | 3 + 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -1624,6 +1624,7 @@ def get_atom(value): """atom = [CFWS] 1*atext [CFWS] + An atom could be an rfc2047 encoded word. """ atom = Atom() if value and value[0] in CFWS_LEADER: @@ -1632,7 +1633,15 @@ if value and value[0] in ATOM_ENDS: raise errors.HeaderParseError( "expected atom but found '{}'".format(value)) - token, value = get_atext(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_atext(value) + else: + token, value = get_atext(value) atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) @@ -1661,12 +1670,22 @@ def get_dot_atom(value): """ dot-atom = [CFWS] dot-atom-text [CFWS] + Any place we can have a dot atom, we could instead have an rfc2047 encoded + word. """ dot_atom = DotAtom() if value[0] in CFWS_LEADER: token, value = get_cfws(value) dot_atom.append(token) - token, value = get_dot_atom_text(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_dot_atom_text(value) + else: + token, value = get_dot_atom_text(value) dot_atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -808,9 +808,13 @@ self.assertEqual(atom[2].comments, ['bar']) def test_get_atom_atom_ends_at_noncfws(self): - atom = self._test_get_x(parser.get_atom, + self._test_get_x(parser.get_atom, 'bob fred', 'bob ', 'bob ', [], 'fred') + def test_get_atom_rfc2047_atom(self): + self._test_get_x(parser.get_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_dot_atom_text def test_get_dot_atom_text(self): @@ -885,6 +889,10 @@ with self.assertRaises(errors.HeaderParseError): parser.get_dot_atom(' (foo) bar.bang. foo') + def test_get_dot_atom_rfc2047_atom(self): + self._test_get_x(parser.get_dot_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_word (if this were black box we'd repeat all the qs/atom tests) def test_get_word_atom_yields_atom(self): @@ -2156,6 +2164,22 @@ self.assertEqual(address[0].token_type, 'mailbox') + def test_get_address_rfc2047_display_name(self): + address = self._test_get_x(parser.get_address, + '=?utf-8?q?=C3=89ric?= ', + '?ric ', + '?ric ', + [], + '') + self.assertEqual(address.token_type, 'address') + self.assertEqual(len(address.mailboxes), 1) + self.assertEqual(address.mailboxes, + address.all_mailboxes) + self.assertEqual(address.mailboxes[0].display_name, + '?ric') + self.assertEqual(address[0].token_type, + 'mailbox') + def test_get_address_empty_group(self): address = self._test_get_x(parser.get_address, 'Monty Python:;', diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -158,6 +158,10 @@ '=?utf-8?q?=C3=89ric?=', '?ric'), + 'rfc2047_quopri_with_regular_text': ( + 'The =?utf-8?q?=C3=89ric=2C?= Himself', + 'The ?ric, Himself'), + } @@ -1119,6 +1123,26 @@ 'example.com', None), + 'rfc2047_atom_is_decoded': + ('=?utf-8?q?=C3=89ric?= ', + [], + '?ric ', + '?ric', + 'foo at example.com', + 'foo', + 'example.com', + None), + + 'rfc2047_atom_in_phrase_is_decoded': + ('The =?utf-8?q?=C3=89ric=2C?= Himself ', + [], + '"The ?ric, Himself" ', + 'The ?ric, Himself', + 'foo at example.com', + 'foo', + 'example.com', + None), + } # XXX: Need many more examples, and in particular some with names in diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -154,6 +154,9 @@ Library ------- +- Issue #18431: The new email header parser now decodes RFC2047 encoded words + in structured headers. + - Issue #18044: The new email header parser was mis-parsing encoded words where an encoded character immediately followed the '?' that follows the CTE character, resulting in a decoding failure. They are now decoded correctly. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:20:13 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 22:20:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDM1?= =?utf-8?q?=3A_Replaced_simple_attribute_container_class_Context_with?= Message-ID: <3bsQVP0HZnz7Lkk@mail.python.org> http://hg.python.org/cpython/rev/fc340fcd43d2 changeset: 84591:fc340fcd43d2 branch: 3.3 parent: 84585:1641a03dbe7b user: Vinay Sajip date: Fri Jul 12 21:10:19 2013 +0100 summary: Issue #18435: Replaced simple attribute container class Context with types.SimpleNamespace. files: Lib/venv/__init__.py | 9 ++------- 1 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -37,15 +37,10 @@ import threading except ImportError: threading = None +import types logger = logging.getLogger(__name__) -class Context: - """ - Holds information about a current venv creation/upgrade request. - """ - pass - class EnvBuilder: """ @@ -108,7 +103,7 @@ raise ValueError('Directory exists: %s' % env_dir) if os.path.exists(env_dir) and self.clear: shutil.rmtree(env_dir) - context = Context() + context = types.SimpleNamespace() context.env_dir = env_dir context.env_name = os.path.split(env_dir)[1] context.prompt = '(%s) ' % context.env_name -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:20:14 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 22:20:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2318435=3A_Merged_fix_from_3=2E3=2E?= Message-ID: <3bsQVQ2dV1z7Ljl@mail.python.org> http://hg.python.org/cpython/rev/113bfefbe5c5 changeset: 84592:113bfefbe5c5 parent: 84586:24a55f04a571 parent: 84591:fc340fcd43d2 user: Vinay Sajip date: Fri Jul 12 21:13:01 2013 +0100 summary: Closes #18435: Merged fix from 3.3. files: Lib/venv/__init__.py | 9 ++------- 1 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -37,15 +37,10 @@ import threading except ImportError: threading = None +import types logger = logging.getLogger(__name__) -class Context: - """ - Holds information about a current venv creation/upgrade request. - """ - pass - class EnvBuilder: """ @@ -116,7 +111,7 @@ if os.path.exists(env_dir) and self.clear: self.clear_directory(env_dir) - context = Context() + context = types.SimpleNamespace() context.env_dir = env_dir context.env_name = os.path.split(env_dir)[1] context.prompt = '(%s) ' % context.env_name -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:20:15 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 22:20:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merged_upstream_changes=2E?= Message-ID: <3bsQVR5kpnz7Llc@mail.python.org> http://hg.python.org/cpython/rev/bd1465ec0199 changeset: 84593:bd1465ec0199 parent: 84592:113bfefbe5c5 parent: 84590:693aec04f9cd user: Vinay Sajip date: Fri Jul 12 21:18:49 2013 +0100 summary: Merged upstream changes. files: Lib/email/_header_value_parser.py | 23 ++++++++- Lib/test/test_email/test__header_value_parser.py | 26 +++++++++- Lib/test/test_email/test_headerregistry.py | 24 +++++++++ Misc/NEWS | 3 + 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -1624,6 +1624,7 @@ def get_atom(value): """atom = [CFWS] 1*atext [CFWS] + An atom could be an rfc2047 encoded word. """ atom = Atom() if value and value[0] in CFWS_LEADER: @@ -1632,7 +1633,15 @@ if value and value[0] in ATOM_ENDS: raise errors.HeaderParseError( "expected atom but found '{}'".format(value)) - token, value = get_atext(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_atext(value) + else: + token, value = get_atext(value) atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) @@ -1661,12 +1670,22 @@ def get_dot_atom(value): """ dot-atom = [CFWS] dot-atom-text [CFWS] + Any place we can have a dot atom, we could instead have an rfc2047 encoded + word. """ dot_atom = DotAtom() if value[0] in CFWS_LEADER: token, value = get_cfws(value) dot_atom.append(token) - token, value = get_dot_atom_text(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_dot_atom_text(value) + else: + token, value = get_dot_atom_text(value) dot_atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -808,9 +808,13 @@ self.assertEqual(atom[2].comments, ['bar']) def test_get_atom_atom_ends_at_noncfws(self): - atom = self._test_get_x(parser.get_atom, + self._test_get_x(parser.get_atom, 'bob fred', 'bob ', 'bob ', [], 'fred') + def test_get_atom_rfc2047_atom(self): + self._test_get_x(parser.get_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_dot_atom_text def test_get_dot_atom_text(self): @@ -885,6 +889,10 @@ with self.assertRaises(errors.HeaderParseError): parser.get_dot_atom(' (foo) bar.bang. foo') + def test_get_dot_atom_rfc2047_atom(self): + self._test_get_x(parser.get_dot_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_word (if this were black box we'd repeat all the qs/atom tests) def test_get_word_atom_yields_atom(self): @@ -2156,6 +2164,22 @@ self.assertEqual(address[0].token_type, 'mailbox') + def test_get_address_rfc2047_display_name(self): + address = self._test_get_x(parser.get_address, + '=?utf-8?q?=C3=89ric?= ', + '?ric ', + '?ric ', + [], + '') + self.assertEqual(address.token_type, 'address') + self.assertEqual(len(address.mailboxes), 1) + self.assertEqual(address.mailboxes, + address.all_mailboxes) + self.assertEqual(address.mailboxes[0].display_name, + '?ric') + self.assertEqual(address[0].token_type, + 'mailbox') + def test_get_address_empty_group(self): address = self._test_get_x(parser.get_address, 'Monty Python:;', diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -158,6 +158,10 @@ '=?utf-8?q?=C3=89ric?=', '?ric'), + 'rfc2047_quopri_with_regular_text': ( + 'The =?utf-8?q?=C3=89ric=2C?= Himself', + 'The ?ric, Himself'), + } @@ -1119,6 +1123,26 @@ 'example.com', None), + 'rfc2047_atom_is_decoded': + ('=?utf-8?q?=C3=89ric?= ', + [], + '?ric ', + '?ric', + 'foo at example.com', + 'foo', + 'example.com', + None), + + 'rfc2047_atom_in_phrase_is_decoded': + ('The =?utf-8?q?=C3=89ric=2C?= Himself ', + [], + '"The ?ric, Himself" ', + 'The ?ric, Himself', + 'foo at example.com', + 'foo', + 'example.com', + None), + } # XXX: Need many more examples, and in particular some with names in diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -154,6 +154,9 @@ Library ------- +- Issue #18431: The new email header parser now decodes RFC2047 encoded words + in structured headers. + - Issue #18044: The new email header parser was mis-parsing encoded words where an encoded character immediately followed the '?' that follows the CTE character, resulting in a decoding failure. They are now decoded correctly. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:20:17 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 22:20:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_Merged_upstream_changes=2E?= Message-ID: <3bsQVT20wTz7Ll0@mail.python.org> http://hg.python.org/cpython/rev/4dc01c6f9741 changeset: 84594:4dc01c6f9741 branch: 3.3 parent: 84591:fc340fcd43d2 parent: 84589:d30e9bbabc09 user: Vinay Sajip date: Fri Jul 12 21:19:41 2013 +0100 summary: Merged upstream changes. files: Lib/email/_header_value_parser.py | 23 ++++++++- Lib/test/test_email/test__header_value_parser.py | 26 +++++++++- Lib/test/test_email/test_headerregistry.py | 24 +++++++++ Misc/NEWS | 3 + 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -1627,6 +1627,7 @@ def get_atom(value): """atom = [CFWS] 1*atext [CFWS] + An atom could be an rfc2047 encoded word. """ atom = Atom() if value and value[0] in CFWS_LEADER: @@ -1635,7 +1636,15 @@ if value and value[0] in ATOM_ENDS: raise errors.HeaderParseError( "expected atom but found '{}'".format(value)) - token, value = get_atext(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_atext(value) + else: + token, value = get_atext(value) atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) @@ -1664,12 +1673,22 @@ def get_dot_atom(value): """ dot-atom = [CFWS] dot-atom-text [CFWS] + Any place we can have a dot atom, we could instead have an rfc2047 encoded + word. """ dot_atom = DotAtom() if value[0] in CFWS_LEADER: token, value = get_cfws(value) dot_atom.append(token) - token, value = get_dot_atom_text(value) + if value.startswith('=?'): + try: + token, value = get_encoded_word(value) + except errors.HeaderParseError: + # XXX: need to figure out how to register defects when + # appropriate here. + token, value = get_dot_atom_text(value) + else: + token, value = get_dot_atom_text(value) dot_atom.append(token) if value and value[0] in CFWS_LEADER: token, value = get_cfws(value) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -808,9 +808,13 @@ self.assertEqual(atom[2].comments, ['bar']) def test_get_atom_atom_ends_at_noncfws(self): - atom = self._test_get_x(parser.get_atom, + self._test_get_x(parser.get_atom, 'bob fred', 'bob ', 'bob ', [], 'fred') + def test_get_atom_rfc2047_atom(self): + self._test_get_x(parser.get_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_dot_atom_text def test_get_dot_atom_text(self): @@ -885,6 +889,10 @@ with self.assertRaises(errors.HeaderParseError): parser.get_dot_atom(' (foo) bar.bang. foo') + def test_get_dot_atom_rfc2047_atom(self): + self._test_get_x(parser.get_dot_atom, + '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '') + # get_word (if this were black box we'd repeat all the qs/atom tests) def test_get_word_atom_yields_atom(self): @@ -2156,6 +2164,22 @@ self.assertEqual(address[0].token_type, 'mailbox') + def test_get_address_rfc2047_display_name(self): + address = self._test_get_x(parser.get_address, + '=?utf-8?q?=C3=89ric?= ', + '?ric ', + '?ric ', + [], + '') + self.assertEqual(address.token_type, 'address') + self.assertEqual(len(address.mailboxes), 1) + self.assertEqual(address.mailboxes, + address.all_mailboxes) + self.assertEqual(address.mailboxes[0].display_name, + '?ric') + self.assertEqual(address[0].token_type, + 'mailbox') + def test_get_address_empty_group(self): address = self._test_get_x(parser.get_address, 'Monty Python:;', diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -158,6 +158,10 @@ '=?utf-8?q?=C3=89ric?=', '?ric'), + 'rfc2047_quopri_with_regular_text': ( + 'The =?utf-8?q?=C3=89ric=2C?= Himself', + 'The ?ric, Himself'), + } @@ -1119,6 +1123,26 @@ 'example.com', None), + 'rfc2047_atom_is_decoded': + ('=?utf-8?q?=C3=89ric?= ', + [], + '?ric ', + '?ric', + 'foo at example.com', + 'foo', + 'example.com', + None), + + 'rfc2047_atom_in_phrase_is_decoded': + ('The =?utf-8?q?=C3=89ric=2C?= Himself ', + [], + '"The ?ric, Himself" ', + 'The ?ric, Himself', + 'foo at example.com', + 'foo', + 'example.com', + None), + } # XXX: Need many more examples, and in particular some with names in diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,9 @@ Library ------- +- Issue #18431: The new email header parser now decodes RFC2047 encoded words + in structured headers. + - Issue #18044: The new email header parser was mis-parsing encoded words where an encoded character immediately followed the '?' that follows the CTE character, resulting in a decoding failure. They are now decoded correctly. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:46:17 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 22:46:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDM0?= =?utf-8?q?=3A_Updated_example_script_to_tidy_up_resources=2E?= Message-ID: <3bsR4T4kglz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/f8c3d05994e4 changeset: 84595:f8c3d05994e4 branch: 3.3 user: Vinay Sajip date: Fri Jul 12 21:44:35 2013 +0100 summary: Issue #18434: Updated example script to tidy up resources. files: Doc/library/venv.rst | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -262,6 +262,7 @@ else: sys.stderr.write(s.decode('utf-8')) sys.stderr.flush() + stream.close() def install_script(self, context, name, url): _, _, path, _, _, _ = urlparse(url) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:46:18 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 22:46:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merged_changes=2E?= Message-ID: <3bsR4V6Zfrz7Ljq@mail.python.org> http://hg.python.org/cpython/rev/b4650f08735f changeset: 84596:b4650f08735f parent: 84593:bd1465ec0199 parent: 84595:f8c3d05994e4 user: Vinay Sajip date: Fri Jul 12 21:46:05 2013 +0100 summary: Merged changes. files: Doc/library/venv.rst | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -261,6 +261,7 @@ else: sys.stderr.write(s.decode('utf-8')) sys.stderr.flush() + stream.close() def install_script(self, context, name, url): _, _, path, _, _, _ = urlparse(url) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:54:23 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 22:54:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDMz?= =?utf-8?q?=3A_Clarified_venv_documentation=2E?= Message-ID: <3bsRFq1Y0qz7Lkg@mail.python.org> http://hg.python.org/cpython/rev/0ca31c07e85e changeset: 84597:0ca31c07e85e branch: 3.3 parent: 84595:f8c3d05994e4 user: Vinay Sajip date: Fri Jul 12 21:52:51 2013 +0100 summary: Issue #18433: Clarified venv documentation. files: Doc/library/venv.rst | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -125,11 +125,13 @@ :meth:`create_configuration`, :meth:`setup_python`, :meth:`setup_scripts` and :meth:`post_setup` can be overridden. - .. method:: create_directories(env_dir) + .. method:: ensure_directories(env_dir) Creates the environment directory and all necessary directories, and returns a context object. This is just a holder for attributes (such as - paths), for use by the other methods. + paths), for use by the other methods. The directories are allowed to + exist already, as long as either ``clear`` or ``upgrade`` were + specified to allow operating on an existing environment directory. .. method:: create_configuration(context) @@ -138,7 +140,10 @@ .. method:: setup_python(context) Creates a copy of the Python executable (and, under Windows, DLLs) in - the environment. + the environment. On a POSIX system, if a specific executable + ``python3.x`` was used, symlinks to ``python`` and ``python3`` will be + created pointing to that executable, unless files with those names + already exist. .. method:: setup_scripts(context) @@ -175,6 +180,8 @@ * ``__VENV_PYTHON__`` is replaced with the absolute path of the environment's executable. + The directories are allowed to exist (for when an existing environment + is being upgraded). There is also a module-level convenience function: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 12 22:54:24 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 12 Jul 2013 22:54:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2318433=3A_Merged_documentation_update_from_3=2E?= =?utf-8?q?3=2E?= Message-ID: <3bsRFr3N3qz7Lkg@mail.python.org> http://hg.python.org/cpython/rev/d292635314c9 changeset: 84598:d292635314c9 parent: 84596:b4650f08735f parent: 84597:0ca31c07e85e user: Vinay Sajip date: Fri Jul 12 21:54:12 2013 +0100 summary: Closes #18433: Merged documentation update from 3.3. files: Doc/library/venv.rst | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -124,11 +124,13 @@ :meth:`create_configuration`, :meth:`setup_python`, :meth:`setup_scripts` and :meth:`post_setup` can be overridden. - .. method:: create_directories(env_dir) + .. method:: ensure_directories(env_dir) Creates the environment directory and all necessary directories, and returns a context object. This is just a holder for attributes (such as - paths), for use by the other methods. + paths), for use by the other methods. The directories are allowed to + exist already, as long as either ``clear`` or ``upgrade`` were + specified to allow operating on an existing environment directory. .. method:: create_configuration(context) @@ -137,7 +139,10 @@ .. method:: setup_python(context) Creates a copy of the Python executable (and, under Windows, DLLs) in - the environment. + the environment. On a POSIX system, if a specific executable + ``python3.x`` was used, symlinks to ``python`` and ``python3`` will be + created pointing to that executable, unless files with those names + already exist. .. method:: setup_scripts(context) @@ -174,6 +179,8 @@ * ``__VENV_PYTHON__`` is replaced with the absolute path of the environment's executable. + The directories are allowed to exist (for when an existing environment + is being upgraded). There is also a module-level convenience function: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 00:11:02 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 13 Jul 2013 00:11:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_PEP_448=3A_Additional_Unp?= =?utf-8?q?acking_Generalizations?= Message-ID: <3bsSyG2Pt3z7Ll9@mail.python.org> http://hg.python.org/peps/rev/5a20b57afda7 changeset: 4992:5a20b57afda7 user: Brett Cannon date: Fri Jul 12 18:10:56 2013 -0400 summary: Add PEP 448: Additional Unpacking Generalizations by Joshua Landau. files: pep-0448.txt | 247 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 247 insertions(+), 0 deletions(-) diff --git a/pep-0448.txt b/pep-0448.txt new file mode 100644 --- /dev/null +++ b/pep-0448.txt @@ -0,0 +1,247 @@ +PEP: 448 +Title: Additional Unpacking Generalizations +Version: $Revision$ +Last-Modified: $Date$ +Author: Joshua Landau +Discussions-To: python-ideas at python.org +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 29-Jun-2013 +Python-Version: 3.4 +Post-History: + + +Abstract +======== + +This PEP proposes extended usages of the ``*`` iterable unpacking +operator to allow unpacking in more positions, an arbitrary number of +times, and in several additional circumstances. + +Specifically: + +Arbitrarily positioned unpacking operators:: + + >>> print(*[1], *[2], 3) + 1 2 3 + >>> dict(**{'x': 1}, y=3, **{'z': 2}) + {'x': 1, 'y': 2, 'z': 3} + +Function calls currently have the restriction that keyword arguments +must follow positional arguments and ``**`` unpackings must additionally +follow ``*`` unpackings. Because of the new levity for ``*`` and ``**`` +unpackings, it may be advisable to lift some or all of these +restrictions. + +As currently, if an argument is given multiple times - such as a +positional argument given both positionally and by keyword - a +TypeError is raised. + +Unpacking is proposed to be allowed inside tuples, lists, sets, +dictionaries and comprehensions:: + + >>> *range(4), 4 + (0, 1, 2, 3, 4) + >>> [*range(4), 4] + [0, 1, 2, 3, 4] + >>> {*range(4), 4} + {0, 1, 2, 3, 4} + >>> {'x': 1, **{'y': 2}} + {'x': 1, 'y': 2} + + >>> ranges = [range(i) for i in range(5)] + >>> [*item for item in ranges] + [0, 0, 1, 0, 1, 2, 0, 1, 2, 3] + + +Rationale +========= + +Current usage of the ``*`` iterable unpacking operator features +unnecessary restrictions that can harm readability. + +Unpacking multiple times has an obvious rationale. When you want to +unpack several iterables into a function definition or follow an unpack +with more positional arguments, the most natural way would be to write:: + + function(**kw_arguments, **more_arguments) + + function(*arguments, argument) + +Simple examples where this is useful are ``print`` and ``str.format``. +Instead, you could be forced to write:: + + kwargs = dict(kw_arguments) + kwargs.update(more_arguments) + function(**kwargs) + + args = list(arguments) + args.append(arg) + function(*args) + +or, if you know to do so:: + + from collections import ChainMap + function(**ChainMap(more_arguments, arguments)) + + from itertools import chain + function(*chain(args, [arg])) + +which add unnecessary line-noise and, with the first methods, causes +duplication of work. + + +There are two primary rationales for unpacking inside of containers. +Firstly there is a symmetry of assignment, where ``fst, *other, lst = +elems`` and ``elems = fst, *other, lst`` are approximate inverses, +ignoring the specifics of types. This, in effect, simplifies the +language by removing special cases. + +Secondly, it vastly simplifies types of "addition" such as combining +dictionaries, and does so in an unambiguous and well-defined way:: + + combination = {**first_dictionary, "x": 1, "y": 2} + +instead of:: + + combination = first_dictionary.copy() + combination.update({"x": 1, "y": 2}) + +which is especially important in contexts where expressions are +preferred. This is also useful as a more readable way of summing +iterables into a list, such as ``my_list + list(my_tuple) + +list(my_range)`` which is now equivalent to just ``[*my_list, +*my_tuple, *my_range]``. + + +The addition of unpacking to comprehensions is a logical extension. +It's usage will primarily be a neat replacement for ``[i for j in +2D_list for i in j]``, as the more readable ``[*l for l in 2D_list]``. +Other uses are possible, but expected to occur rarely. + + +Specification +============= + +Function calls may accept an unbound number of ``*`` and ``**`` +unpackings. There will be no restriction of the order of positional +arguments with relation to ``*`` unpackings nor any restriction of the +order of keyword arguments with relation to ``**`` unpackings. + +Function calls currently have the restriction that keyword arguments +must follow positional arguments and ``**`` unpackings must additionally +follow ``*`` unpackings. Because of the new levity for ``*`` and ``**`` +unpackings, it may be advisable to list some or all of these +restrictions. + +As currently, if an argument is given multiple times - such as a +positional argument given both positionally and by keyword - a +TypeError is raised. + +If the restrictions are kept, a function call will look like this:: + + function( + argument or *args, argument or *args, ..., + kwargument or *args, kwargument or *args, ..., + kwargument or **kwargs, kwargument or **kwargs, ... + ) + +If they are removed completely, a function call will look like this:: + + function( + argument or keyword_argument or `*`args or **kwargs, + argument or keyword_argument or `*`args or **kwargs, + ... + ) + + +Tuples, lists, sets and dictionaries will allow unpacking. This will +act as if the elements from unpacked items were inserted in order at +the site of unpacking, much as happens in unpacking in a function-call. +Dictionaries require ``**`` unpacking; all the others require ``*`` unpacking. +A dictionary's key remain in a right-to-left priority order, so +``{**{'a': 1}, 'a': 2, **{'a': 3}}`` evaluates to ``{'a': 3}``. There +is no restriction on the number or position of unpackings. + +Comprehensions, by simple extension, will support unpacking. As before, +dictionaries require ``**`` unpacking, all the others require ``*`` +unpacking and key priorities are unchanged. + +Examples include:: + + {*[1, 2, 3], 4, 5, *{6, 7, 8}} + + (*e for e in [[1], [3, 4, 5], [2]]) + + {**dictionary for dictionary in (globals(), locals())} + + {**locals(), "override": None} + + +Disadvantages +============= + +If the current restrictions for function call arguments (keyword +arguments must follow positional arguments and ``**`` unpackings must +additionally follow ``*`` unpackings) are kept, the allowable orders +for arguments in a function call is more complicated than before. +The simplest explanation for the rules may be "positional arguments +come first and keyword arguments follow, but ``*`` unpackings are +allowed after keyword arguments". + +If the current restrictions are lifted, there are no obvious gains to +code as the only new orders that are allowed look silly: ``f(a, e=e, +d=d, b, c)`` being a simpler example. + + +Whilst ``*elements, = iterable`` causes ``elements`` to be a list, +``elements = *iterable,`` causes ``elements`` to be a tuple. The +reason for this may not be obvious at first glance and may confuse +people unfamiliar with the construct. + + +Implementation +============== + +An implementation for an old version of Python 3 is found at Issue +2292 on bug tracker [1]_, although several changes should be made: + +- It has yet to be updated to the most recent Python version + +- It features a now redundant replacement for "yield from" which + should be removed + +- It also loses support for calling function with keyword arguments before + positional arguments, which is an unnecessary backwards-incompatible change + +- If the restrictions on the order of arguments in a function call are + partially or fully lifted, they would need to be included + + +References +========== + +.. [1] Issue 2292, "Missing `*`-unpacking generalizations", Thomas Wouters + (http://bugs.python.org/issue2292) + +.. [2] Discussion on Python-ideas list, + "list / array comprehensions extension", Alexander Heger + (http://mail.python.org/pipermail/python-ideas/2011-December/013097.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 Sat Jul 13 00:21:55 2013 From: python-checkins at python.org (r.david.murray) Date: Sat, 13 Jul 2013 00:21:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4Mzg5OiBDbGFy?= =?utf-8?q?ify_that_relpath_does_not_access_the_file_system=2E?= Message-ID: <3bsTBq3TPmzS77@mail.python.org> http://hg.python.org/cpython/rev/70837970c5d8 changeset: 84599:70837970c5d8 branch: 3.3 parent: 84597:0ca31c07e85e user: R David Murray date: Fri Jul 12 17:43:11 2013 -0400 summary: #18389: Clarify that relpath does not access the file system. Initial patch by Madison May. files: Doc/library/os.path.rst | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -234,8 +234,10 @@ .. function:: relpath(path, start=None) - Return a relative filepath to *path* either from the current directory or from - an optional *start* point. + Return a relative filepath to *path* either from the current directory or + from an optional *start* directory. This is a path computation: the + filesystem is not accessed to confirm the existence or nature of *path* or + *start*. *start* defaults to :attr:`os.curdir`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 00:21:56 2013 From: python-checkins at python.org (r.david.murray) Date: Sat, 13 Jul 2013 00:21:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=2318389=3A_Clarify_that_relpath_does_not_access_the_fil?= =?utf-8?q?e_system=2E?= Message-ID: <3bsTBr5JBVz7Ljj@mail.python.org> http://hg.python.org/cpython/rev/7de05609e390 changeset: 84600:7de05609e390 parent: 84598:d292635314c9 parent: 84599:70837970c5d8 user: R David Murray date: Fri Jul 12 17:43:53 2013 -0400 summary: #18389: Clarify that relpath does not access the file system. Initial patch by Madison May. files: Doc/library/os.path.rst | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -233,8 +233,10 @@ .. function:: relpath(path, start=None) - Return a relative filepath to *path* either from the current directory or from - an optional *start* point. + Return a relative filepath to *path* either from the current directory or + from an optional *start* directory. This is a path computation: the + filesystem is not accessed to confirm the existence or nature of *path* or + *start*. *start* defaults to :attr:`os.curdir`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 00:21:57 2013 From: python-checkins at python.org (r.david.murray) Date: Sat, 13 Jul 2013 00:21:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE4Mzg5OiBDbGFy?= =?utf-8?q?ify_that_relpath_does_not_access_the_file_system=2E?= Message-ID: <3bsTBs6xxyz7Ljx@mail.python.org> http://hg.python.org/cpython/rev/1345d8dbcb19 changeset: 84601:1345d8dbcb19 branch: 2.7 parent: 84551:f53cdd4e2689 user: R David Murray date: Fri Jul 12 18:21:41 2013 -0400 summary: #18389: Clarify that relpath does not access the file system. Initial patch by Madison May. files: Doc/library/os.path.rst | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -236,8 +236,10 @@ .. function:: relpath(path[, start]) - Return a relative filepath to *path* either from the current directory or from - an optional *start* point. + Return a relative filepath to *path* either from the current directory or + from an optional *start* directory. This is a path computation: the + filesystem is not accessed to confirm the existence or nature of *path* or + *start*. *start* defaults to :attr:`os.curdir`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 02:19:07 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 02:19:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MzY1?= =?utf-8?q?=3A_Add_mock_Text_class_and_test_thereof_versus_tk=2EText=2E?= Message-ID: <3bsWp30VWKz7Ljl@mail.python.org> http://hg.python.org/cpython/rev/5ac2ec0a34a5 changeset: 84602:5ac2ec0a34a5 branch: 2.7 user: Terry Jan Reedy date: Fri Jul 12 20:10:17 2013 -0400 summary: Issue #18365: Add mock Text class and test thereof versus tk.Text. Based on patches by Todd.Rovito and Phil Webster. files: Lib/idlelib/idle_test/mock_tk.py | 226 ++++++++++++++++- Lib/idlelib/idle_test/test_text.py | 228 +++++++++++++++++ 2 files changed, 449 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py --- a/Lib/idlelib/idle_test/mock_tk.py +++ b/Lib/idlelib/idle_test/mock_tk.py @@ -1,4 +1,5 @@ """Classes that replace tkinter gui objects used by an object being tested. + A gui object is anything with a master or parent paramenter, which is typically required in spite of what the doc strings say. """ @@ -15,8 +16,10 @@ return self.value class Mbox_func(object): - """Generic mock for messagebox functions. All have same call signature. - Mbox instantiates once for each function. Tester uses attributes. + """Generic mock for messagebox functions, which all have the same signature. + + Instead of displaying a message box, the mock's call method saves the + arguments as instance attributes, which test functions can then examime. """ def __init__(self): self.result = None # The return for all show funcs @@ -30,6 +33,7 @@ class Mbox(object): """Mock for tkinter.messagebox with an Mbox_func for each function. + This module was 'tkMessageBox' in 2.x; hence the 'import as' in 3.x. Example usage in test_module.py for testing functios in module.py: --- @@ -49,9 +53,9 @@ def tearDownClass(cls): module.tkMessageBox = orig_mbox --- - When tkMessageBox functions are the only gui making calls in a method, - this replacement makes the method gui-free and unit-testable. - For 'ask' functions, set func.result return before calling method. + For 'ask' functions, set func.result return value before calling the method + that uses the message function. When tkMessageBox functions are the + only gui alls in a method, this replacement makes the method gui-free, """ askokcancel = Mbox_func() # True or False askquestion = Mbox_func() # 'yes' or 'no' @@ -61,3 +65,215 @@ showerror = Mbox_func() # None showinfo = Mbox_func() # None showwarning = Mbox_func() # None + +from _tkinter import TclError + +class Text(object): + """A semi-functional non-gui replacement for tkinter.Text text editors. + + The mock's data model is that a text is a list of \n-terminated lines. + The mock adds an empty string at the beginning of the list so that the + index of actual lines start at 1, as with Tk. The methods never see this. + Tk initializes files with a terminal \n that cannot be deleted. It is + invisible in the sense that one cannot move the cursor beyond it. + + This class is only tested (and valid) with strings of ascii chars. + For testing, we are not concerned with Tk Text's treatment of, + for instance, 0-width characters or character + accent. + """ + def __init__(self, master=None, cnf={}, **kw): + '''Initialize mock, non-gui, text-only Text widget. + + At present, all args are ignored. Almost all affect visual behavior. + There are just a few Text-only options that affect text behavior. + ''' + self.data = ['', '\n'] + + def index(self, index): + "Return string version of index decoded according to current text." + return "%s.%s" % self._decode(index, endflag=1) + + def _decode(self, index, endflag=0): + """Return a (line, char) tuple of int indexes into self.data. + + This implements .index without converting the result back to a string. + The result is contrained by the number of lines and linelengths of + self.data. For many indexes, the result is initally (1, 0). + + The input index may have any of several possible forms: + * line.char float: converted to 'line.char' string; + * 'line.char' string, where line and char are decimal integers; + * 'line.char lineend', where lineend='lineend' (and char is ignored); + * 'line.end', where end='end' (same as above); + * 'insert', the positions before terminal \n; + * 'end', whose meaning depends on the endflag passed to ._endex. + * 'sel.first' or 'sel.last', where sel is a tag -- not implemented. + """ + if isinstance(index, (float, bytes)): + index = str(index) + try: + index=index.lower() + except AttributeError: + raise TclError('bad text index "%s"' % index) from None + + lastline = len(self.data) - 1 # same as number of text lines + if index == 'insert': + return lastline, len(self.data[lastline]) - 1 + elif index == 'end': + return self._endex(endflag) + + line, char = index.split('.') + line = int(line) + + # Out of bounds line becomes first or last ('end') index + if line < 1: + return 1, 0 + elif line > lastline: + return self._endex(endflag) + + linelength = len(self.data[line]) -1 # position before/at \n + if char.endswith(' lineend') or char == 'end': + return line, linelength + # Tk requires that ignored chars before ' lineend' be valid int + + # Out of bounds char becomes first or last index of line + char = int(char) + if char < 0: + char = 0 + elif char > linelength: + char = linelength + return line, char + + def _endex(self, endflag): + '''Return position for 'end' or line overflow corresponding to endflag. + + -1: position before terminal \n; for .insert(), .delete + 0: position after terminal \n; for .get, .delete index 1 + 1: same viewed as begininning of non-existent next line (for .index) + ''' + n = len(self.data) + if endflag == 1: + return n, 0 + else: + n -= 1 + return n, len(self.data[n]) + endflag + + + def insert(self, index, chars): + "Insert chars before the character at index." + + if not chars: # ''.splitlines() is [], not [''] + return + chars = chars.splitlines(True) + if chars[-1][-1] == '\n': + chars.append('') + line, char = self._decode(index, -1) + before = self.data[line][:char] + after = self.data[line][char:] + self.data[line] = before + chars[0] + self.data[line+1:line+1] = chars[1:] + self.data[line+len(chars)-1] += after + + + def get(self, index1, index2=None): + "Return slice from index1 to index2 (default is 'index1+1')." + + startline, startchar = self._decode(index1) + if index2 is None: + endline, endchar = startline, startchar+1 + else: + endline, endchar = self._decode(index2) + + if startline == endline: + return self.data[startline][startchar:endchar] + else: + lines = [self.data[startline][startchar:]] + for i in range(startline+1, endline): + lines.append(self.data[i]) + lines.append(self.data[endline][:endchar]) + return ''.join(lines) + + + def delete(self, index1, index2=None): + '''Delete slice from index1 to index2 (default is 'index1+1'). + + Adjust default index2 ('index+1) for line ends. + Do not delete the terminal \n at the very end of self.data ([-1][-1]). + ''' + startline, startchar = self._decode(index1, -1) + if index2 is None: + if startchar < len(self.data[startline])-1: + # not deleting \n + endline, endchar = startline, startchar+1 + elif startline < len(self.data) - 1: + # deleting non-terminal \n, convert 'index1+1 to start of next line + endline, endchar = startline+1, 0 + else: + # do not delete terminal \n if index1 == 'insert' + return + else: + endline, endchar = self._decode(index2, -1) + # restricting end position to insert position excludes terminal \n + + if startline == endline and startchar < endchar: + self.data[startline] = self.data[startline][:startchar] + \ + self.data[startline][endchar:] + elif startline < endline: + self.data[startline] = self.data[startline][:startchar] + \ + self.data[endline][endchar:] + startline += 1 + for i in range(startline, endline+1): + del self.data[startline] + + def compare(self, index1, op, index2): + line1, char1 = self._decode(index1) + line2, char2 = self._decode(index2) + if op == '<': + return line1 < line2 or line1 == line2 and char1 < char2 + elif op == '<=': + return line1 < line2 or line1 == line2 and char1 <= char2 + elif op == '>': + return line1 > line2 or line1 == line2 and char1 > char2 + elif op == '>=': + return line1 > line2 or line1 == line2 and char1 >= char2 + elif op == '==': + return line1 == line2 and char1 == char2 + elif op == '!=': + return line1 != line2 or char1 != char2 + else: + raise TclError('''bad comparison operator "%s":''' + '''must be <, <=, ==, >=, >, or !=''' % op) + + # The following Text methods normally do something and return None. + # Whether doing nothing is sufficient for a test will depend on the test. + + def mark_set(self, name, index): + "Set mark *name* before the character at index." + pass + + def mark_unset(self, *markNames): + "Delete all marks in markNames." + + def tag_remove(self, tagName, index1, index2=None): + "Remove tag tagName from all characters between index1 and index2." + pass + + # The following Text methods affect the graphics screen and return None. + # Doing nothing should always be sufficient for tests. + + def scan_dragto(self, x, y): + "Adjust the view of the text according to scan_mark" + + def scan_mark(self, x, y): + "Remember the current X, Y coordinates." + + def see(self, index): + "Scroll screen to make the character at INDEX is visible." + pass + + # The following is a Misc method inheritet by Text. + # It should properly go in a Misc mock, but is included here for now. + + def bind(sequence=None, func=None, add=None): + "Bind to this widget at event sequence a call to function func." + pass diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_text.py @@ -0,0 +1,228 @@ +# Test mock_tk.Text class against tkinter.Text class by running same tests with both. +import unittest +from test.support import requires + +from _tkinter import TclError +import tkinter as tk + +class TextTest(object): + + hw = 'hello\nworld' # usual initial insert after initialization + hwn = hw+'\n' # \n present at initialization, before insert + + Text = None + def setUp(self): + self.text = self.Text() + + def test_init(self): + self.assertEqual(self.text.get('1.0'), '\n') + self.assertEqual(self.text.get('end'), '') + + def test_index_empty(self): + index = self.text.index + + for dex in (-1.0, 0.3, '1.-1', '1.0', '1.0 lineend', '1.end', '1.33', + 'insert'): + self.assertEqual(index(dex), '1.0') + + for dex in 'end', 2.0, '2.1', '33.44': + self.assertEqual(index(dex), '2.0') + + def test_index_data(self): + index = self.text.index + self.text.insert('1.0', self.hw) + + for dex in -1.0, 0.3, '1.-1', '1.0': + self.assertEqual(index(dex), '1.0') + + for dex in '1.0 lineend', '1.end', '1.33': + self.assertEqual(index(dex), '1.5') + + for dex in 'end', '33.44': + self.assertEqual(index(dex), '3.0') + + def test_get(self): + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + Equal(get('end'), '') + Equal(get('end', 'end'), '') + Equal(get('1.0'), 'h') + Equal(get('1.0', '1.1'), 'h') + Equal(get('1.0', '1.3'), 'hel') + Equal(get('1.1', '1.3'), 'el') + Equal(get('1.0', '1.0 lineend'), 'hello') + Equal(get('1.0', '1.10'), 'hello') + Equal(get('1.0 lineend'), '\n') + Equal(get('1.1', '2.3'), 'ello\nwor') + Equal(get('1.0', '2.5'), self.hw) + Equal(get('1.0', 'end'), self.hwn) + Equal(get('0.0', '5.0'), self.hwn) + + def test_insert(self): + insert = self.text.insert + get = self.text.get + Equal = self.assertEqual + + insert('1.0', self.hw) + Equal(get('1.0', 'end'), self.hwn) + + insert('1.0', '') # nothing + Equal(get('1.0', 'end'), self.hwn) + + insert('1.0', '*') + Equal(get('1.0', 'end'), '*hello\nworld\n') + + insert('1.0 lineend', '*') + Equal(get('1.0', 'end'), '*hello*\nworld\n') + + insert('2.3', '*') + Equal(get('1.0', 'end'), '*hello*\nwor*ld\n') + + insert('end', 'x') + Equal(get('1.0', 'end'), '*hello*\nwor*ldx\n') + + insert('1.4', 'x\n') + Equal(get('1.0', 'end'), '*helx\nlo*\nwor*ldx\n') + + def test_no_delete(self): + # if index1 == 'insert' or 'end' or >= end, there is no deletion + delete = self.text.delete + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + delete('insert') + Equal(get('1.0', 'end'), self.hwn) + + delete('end') + Equal(get('1.0', 'end'), self.hwn) + + delete('insert', 'end') + Equal(get('1.0', 'end'), self.hwn) + + delete('insert', '5.5') + Equal(get('1.0', 'end'), self.hwn) + + delete('1.4', '1.0') + Equal(get('1.0', 'end'), self.hwn) + + delete('1.4', '1.4') + Equal(get('1.0', 'end'), self.hwn) + + def test_delete_char(self): + delete = self.text.delete + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + delete('1.0') + Equal(get('1.0', '1.end'), 'ello') + + delete('1.0', '1.1') + Equal(get('1.0', '1.end'), 'llo') + + # delete \n and combine 2 lines into 1 + delete('1.end') + Equal(get('1.0', '1.end'), 'lloworld') + + self.text.insert('1.3', '\n') + delete('1.10') + Equal(get('1.0', '1.end'), 'lloworld') + + self.text.insert('1.3', '\n') + delete('1.3', '2.0') + Equal(get('1.0', '1.end'), 'lloworld') + + def test_delete_slice(self): + delete = self.text.delete + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + delete('1.0', '1.0 lineend') + Equal(get('1.0', 'end'), '\nworld\n') + + delete('1.0', 'end') + Equal(get('1.0', 'end'), '\n') + + self.text.insert('1.0', self.hw) + delete('1.0', '2.0') + Equal(get('1.0', 'end'), 'world\n') + + delete('1.0', 'end') + Equal(get('1.0', 'end'), '\n') + + self.text.insert('1.0', self.hw) + delete('1.2', '2.3') + Equal(get('1.0', 'end'), 'held\n') + + def test_multiple_lines(self): # insert and delete + self.text.insert('1.0', 'hello') + + self.text.insert('1.3', '1\n2\n3\n4\n5') + self.assertEqual(self.text.get('1.0', 'end'), 'hel1\n2\n3\n4\n5lo\n') + + self.text.delete('1.3', '5.1') + self.assertEqual(self.text.get('1.0', 'end'), 'hello\n') + + def test_compare(self): + compare = self.text.compare + Equal = self.assertEqual + # need data so indexes not squished to 1,0 + self.text.insert('1.0', 'First\nSecond\nThird\n') + + self.assertRaises(TclError, compare, '2.2', 'op', '2.2') + + for op, less1, less0, equal, greater0, greater1 in ( + ('<', True, True, False, False, False), + ('<=', True, True, True, False, False), + ('>', False, False, False, True, True), + ('>=', False, False, True, True, True), + ('==', False, False, True, False, False), + ('!=', True, True, False, True, True), + ): + Equal(compare('1.1', op, '2.2'), less1, op) + Equal(compare('2.1', op, '2.2'), less0, op) + Equal(compare('2.2', op, '2.2'), equal, op) + Equal(compare('2.3', op, '2.2'), greater0, op) + Equal(compare('3.3', op, '2.2'), greater1, op) + + +class MockTextTest(TextTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + from idlelib.idle_test.mock_tk import Text + cls.Text = Text + + def test_decode(self): + # test endflags (-1, 0) not tested by test_index (which uses +1) + decode = self.text._decode + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + Equal(decode('end', -1), (2, 5)) + Equal(decode('3.1', -1), (2, 5)) + Equal(decode('end', 0), (2, 6)) + Equal(decode('3.1', 0), (2, 6)) + + +class TkTextTest(TextTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + from tkinter import Tk, Text + cls.Text = Text + cls.root = Tk() + + @classmethod + def tearDownClass(cls): + cls.root.destroy() + + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 02:19:08 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 02:19:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzY1?= =?utf-8?q?=3A_Add_mock_Text_class_and_test_thereof_versus_tk=2EText=2E?= Message-ID: <3bsWp44f8gz7LkM@mail.python.org> http://hg.python.org/cpython/rev/8f13fb4c5826 changeset: 84603:8f13fb4c5826 branch: 3.3 parent: 84599:70837970c5d8 user: Terry Jan Reedy date: Fri Jul 12 20:10:23 2013 -0400 summary: Issue #18365: Add mock Text class and test thereof versus tk.Text. Based on patches by Todd.Rovito and Phil Webster. files: Lib/idlelib/idle_test/mock_tk.py | 226 ++++++++++++++++- Lib/idlelib/idle_test/test_text.py | 228 +++++++++++++++++ 2 files changed, 449 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py --- a/Lib/idlelib/idle_test/mock_tk.py +++ b/Lib/idlelib/idle_test/mock_tk.py @@ -1,4 +1,5 @@ """Classes that replace tkinter gui objects used by an object being tested. + A gui object is anything with a master or parent paramenter, which is typically required in spite of what the doc strings say. """ @@ -15,8 +16,10 @@ return self.value class Mbox_func: - """Generic mock for messagebox functions. All have same call signature. - Mbox instantiates once for each function. Tester uses attributes. + """Generic mock for messagebox functions, which all have the same signature. + + Instead of displaying a message box, the mock's call method saves the + arguments as instance attributes, which test functions can then examime. """ def __init__(self): self.result = None # The return for all show funcs @@ -30,6 +33,7 @@ class Mbox: """Mock for tkinter.messagebox with an Mbox_func for each function. + This module was 'tkMessageBox' in 2.x; hence the 'import as' in 3.x. Example usage in test_module.py for testing functios in module.py: --- @@ -49,9 +53,9 @@ def tearDownClass(cls): module.tkMessageBox = orig_mbox --- - When tkMessageBox functions are the only gui making calls in a method, - this replacement makes the method gui-free and unit-testable. - For 'ask' functions, set func.result return before calling method. + For 'ask' functions, set func.result return value before calling the method + that uses the message function. When tkMessageBox functions are the + only gui alls in a method, this replacement makes the method gui-free, """ askokcancel = Mbox_func() # True or False askquestion = Mbox_func() # 'yes' or 'no' @@ -61,3 +65,215 @@ showerror = Mbox_func() # None showinfo = Mbox_func() # None showwarning = Mbox_func() # None + +from _tkinter import TclError + +class Text: + """A semi-functional non-gui replacement for tkinter.Text text editors. + + The mock's data model is that a text is a list of \n-terminated lines. + The mock adds an empty string at the beginning of the list so that the + index of actual lines start at 1, as with Tk. The methods never see this. + Tk initializes files with a terminal \n that cannot be deleted. It is + invisible in the sense that one cannot move the cursor beyond it. + + This class is only tested (and valid) with strings of ascii chars. + For testing, we are not concerned with Tk Text's treatment of, + for instance, 0-width characters or character + accent. + """ + def __init__(self, master=None, cnf={}, **kw): + '''Initialize mock, non-gui, text-only Text widget. + + At present, all args are ignored. Almost all affect visual behavior. + There are just a few Text-only options that affect text behavior. + ''' + self.data = ['', '\n'] + + def index(self, index): + "Return string version of index decoded according to current text." + return "%s.%s" % self._decode(index, endflag=1) + + def _decode(self, index, endflag=0): + """Return a (line, char) tuple of int indexes into self.data. + + This implements .index without converting the result back to a string. + The result is contrained by the number of lines and linelengths of + self.data. For many indexes, the result is initally (1, 0). + + The input index may have any of several possible forms: + * line.char float: converted to 'line.char' string; + * 'line.char' string, where line and char are decimal integers; + * 'line.char lineend', where lineend='lineend' (and char is ignored); + * 'line.end', where end='end' (same as above); + * 'insert', the positions before terminal \n; + * 'end', whose meaning depends on the endflag passed to ._endex. + * 'sel.first' or 'sel.last', where sel is a tag -- not implemented. + """ + if isinstance(index, (float, bytes)): + index = str(index) + try: + index=index.lower() + except AttributeError: + raise TclError('bad text index "%s"' % index) from None + + lastline = len(self.data) - 1 # same as number of text lines + if index == 'insert': + return lastline, len(self.data[lastline]) - 1 + elif index == 'end': + return self._endex(endflag) + + line, char = index.split('.') + line = int(line) + + # Out of bounds line becomes first or last ('end') index + if line < 1: + return 1, 0 + elif line > lastline: + return self._endex(endflag) + + linelength = len(self.data[line]) -1 # position before/at \n + if char.endswith(' lineend') or char == 'end': + return line, linelength + # Tk requires that ignored chars before ' lineend' be valid int + + # Out of bounds char becomes first or last index of line + char = int(char) + if char < 0: + char = 0 + elif char > linelength: + char = linelength + return line, char + + def _endex(self, endflag): + '''Return position for 'end' or line overflow corresponding to endflag. + + -1: position before terminal \n; for .insert(), .delete + 0: position after terminal \n; for .get, .delete index 1 + 1: same viewed as begininning of non-existent next line (for .index) + ''' + n = len(self.data) + if endflag == 1: + return n, 0 + else: + n -= 1 + return n, len(self.data[n]) + endflag + + + def insert(self, index, chars): + "Insert chars before the character at index." + + if not chars: # ''.splitlines() is [], not [''] + return + chars = chars.splitlines(True) + if chars[-1][-1] == '\n': + chars.append('') + line, char = self._decode(index, -1) + before = self.data[line][:char] + after = self.data[line][char:] + self.data[line] = before + chars[0] + self.data[line+1:line+1] = chars[1:] + self.data[line+len(chars)-1] += after + + + def get(self, index1, index2=None): + "Return slice from index1 to index2 (default is 'index1+1')." + + startline, startchar = self._decode(index1) + if index2 is None: + endline, endchar = startline, startchar+1 + else: + endline, endchar = self._decode(index2) + + if startline == endline: + return self.data[startline][startchar:endchar] + else: + lines = [self.data[startline][startchar:]] + for i in range(startline+1, endline): + lines.append(self.data[i]) + lines.append(self.data[endline][:endchar]) + return ''.join(lines) + + + def delete(self, index1, index2=None): + '''Delete slice from index1 to index2 (default is 'index1+1'). + + Adjust default index2 ('index+1) for line ends. + Do not delete the terminal \n at the very end of self.data ([-1][-1]). + ''' + startline, startchar = self._decode(index1, -1) + if index2 is None: + if startchar < len(self.data[startline])-1: + # not deleting \n + endline, endchar = startline, startchar+1 + elif startline < len(self.data) - 1: + # deleting non-terminal \n, convert 'index1+1 to start of next line + endline, endchar = startline+1, 0 + else: + # do not delete terminal \n if index1 == 'insert' + return + else: + endline, endchar = self._decode(index2, -1) + # restricting end position to insert position excludes terminal \n + + if startline == endline and startchar < endchar: + self.data[startline] = self.data[startline][:startchar] + \ + self.data[startline][endchar:] + elif startline < endline: + self.data[startline] = self.data[startline][:startchar] + \ + self.data[endline][endchar:] + startline += 1 + for i in range(startline, endline+1): + del self.data[startline] + + def compare(self, index1, op, index2): + line1, char1 = self._decode(index1) + line2, char2 = self._decode(index2) + if op == '<': + return line1 < line2 or line1 == line2 and char1 < char2 + elif op == '<=': + return line1 < line2 or line1 == line2 and char1 <= char2 + elif op == '>': + return line1 > line2 or line1 == line2 and char1 > char2 + elif op == '>=': + return line1 > line2 or line1 == line2 and char1 >= char2 + elif op == '==': + return line1 == line2 and char1 == char2 + elif op == '!=': + return line1 != line2 or char1 != char2 + else: + raise TclError('''bad comparison operator "%s":''' + '''must be <, <=, ==, >=, >, or !=''' % op) + + # The following Text methods normally do something and return None. + # Whether doing nothing is sufficient for a test will depend on the test. + + def mark_set(self, name, index): + "Set mark *name* before the character at index." + pass + + def mark_unset(self, *markNames): + "Delete all marks in markNames." + + def tag_remove(self, tagName, index1, index2=None): + "Remove tag tagName from all characters between index1 and index2." + pass + + # The following Text methods affect the graphics screen and return None. + # Doing nothing should always be sufficient for tests. + + def scan_dragto(self, x, y): + "Adjust the view of the text according to scan_mark" + + def scan_mark(self, x, y): + "Remember the current X, Y coordinates." + + def see(self, index): + "Scroll screen to make the character at INDEX is visible." + pass + + # The following is a Misc method inheritet by Text. + # It should properly go in a Misc mock, but is included here for now. + + def bind(sequence=None, func=None, add=None): + "Bind to this widget at event sequence a call to function func." + pass diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_text.py @@ -0,0 +1,228 @@ +# Test mock_tk.Text class against tkinter.Text class by running same tests with both. +import unittest +from test.support import requires + +from _tkinter import TclError +import tkinter as tk + +class TextTest(object): + + hw = 'hello\nworld' # usual initial insert after initialization + hwn = hw+'\n' # \n present at initialization, before insert + + Text = None + def setUp(self): + self.text = self.Text() + + def test_init(self): + self.assertEqual(self.text.get('1.0'), '\n') + self.assertEqual(self.text.get('end'), '') + + def test_index_empty(self): + index = self.text.index + + for dex in (-1.0, 0.3, '1.-1', '1.0', '1.0 lineend', '1.end', '1.33', + 'insert'): + self.assertEqual(index(dex), '1.0') + + for dex in 'end', 2.0, '2.1', '33.44': + self.assertEqual(index(dex), '2.0') + + def test_index_data(self): + index = self.text.index + self.text.insert('1.0', self.hw) + + for dex in -1.0, 0.3, '1.-1', '1.0': + self.assertEqual(index(dex), '1.0') + + for dex in '1.0 lineend', '1.end', '1.33': + self.assertEqual(index(dex), '1.5') + + for dex in 'end', '33.44': + self.assertEqual(index(dex), '3.0') + + def test_get(self): + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + Equal(get('end'), '') + Equal(get('end', 'end'), '') + Equal(get('1.0'), 'h') + Equal(get('1.0', '1.1'), 'h') + Equal(get('1.0', '1.3'), 'hel') + Equal(get('1.1', '1.3'), 'el') + Equal(get('1.0', '1.0 lineend'), 'hello') + Equal(get('1.0', '1.10'), 'hello') + Equal(get('1.0 lineend'), '\n') + Equal(get('1.1', '2.3'), 'ello\nwor') + Equal(get('1.0', '2.5'), self.hw) + Equal(get('1.0', 'end'), self.hwn) + Equal(get('0.0', '5.0'), self.hwn) + + def test_insert(self): + insert = self.text.insert + get = self.text.get + Equal = self.assertEqual + + insert('1.0', self.hw) + Equal(get('1.0', 'end'), self.hwn) + + insert('1.0', '') # nothing + Equal(get('1.0', 'end'), self.hwn) + + insert('1.0', '*') + Equal(get('1.0', 'end'), '*hello\nworld\n') + + insert('1.0 lineend', '*') + Equal(get('1.0', 'end'), '*hello*\nworld\n') + + insert('2.3', '*') + Equal(get('1.0', 'end'), '*hello*\nwor*ld\n') + + insert('end', 'x') + Equal(get('1.0', 'end'), '*hello*\nwor*ldx\n') + + insert('1.4', 'x\n') + Equal(get('1.0', 'end'), '*helx\nlo*\nwor*ldx\n') + + def test_no_delete(self): + # if index1 == 'insert' or 'end' or >= end, there is no deletion + delete = self.text.delete + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + delete('insert') + Equal(get('1.0', 'end'), self.hwn) + + delete('end') + Equal(get('1.0', 'end'), self.hwn) + + delete('insert', 'end') + Equal(get('1.0', 'end'), self.hwn) + + delete('insert', '5.5') + Equal(get('1.0', 'end'), self.hwn) + + delete('1.4', '1.0') + Equal(get('1.0', 'end'), self.hwn) + + delete('1.4', '1.4') + Equal(get('1.0', 'end'), self.hwn) + + def test_delete_char(self): + delete = self.text.delete + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + delete('1.0') + Equal(get('1.0', '1.end'), 'ello') + + delete('1.0', '1.1') + Equal(get('1.0', '1.end'), 'llo') + + # delete \n and combine 2 lines into 1 + delete('1.end') + Equal(get('1.0', '1.end'), 'lloworld') + + self.text.insert('1.3', '\n') + delete('1.10') + Equal(get('1.0', '1.end'), 'lloworld') + + self.text.insert('1.3', '\n') + delete('1.3', '2.0') + Equal(get('1.0', '1.end'), 'lloworld') + + def test_delete_slice(self): + delete = self.text.delete + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + delete('1.0', '1.0 lineend') + Equal(get('1.0', 'end'), '\nworld\n') + + delete('1.0', 'end') + Equal(get('1.0', 'end'), '\n') + + self.text.insert('1.0', self.hw) + delete('1.0', '2.0') + Equal(get('1.0', 'end'), 'world\n') + + delete('1.0', 'end') + Equal(get('1.0', 'end'), '\n') + + self.text.insert('1.0', self.hw) + delete('1.2', '2.3') + Equal(get('1.0', 'end'), 'held\n') + + def test_multiple_lines(self): # insert and delete + self.text.insert('1.0', 'hello') + + self.text.insert('1.3', '1\n2\n3\n4\n5') + self.assertEqual(self.text.get('1.0', 'end'), 'hel1\n2\n3\n4\n5lo\n') + + self.text.delete('1.3', '5.1') + self.assertEqual(self.text.get('1.0', 'end'), 'hello\n') + + def test_compare(self): + compare = self.text.compare + Equal = self.assertEqual + # need data so indexes not squished to 1,0 + self.text.insert('1.0', 'First\nSecond\nThird\n') + + self.assertRaises(TclError, compare, '2.2', 'op', '2.2') + + for op, less1, less0, equal, greater0, greater1 in ( + ('<', True, True, False, False, False), + ('<=', True, True, True, False, False), + ('>', False, False, False, True, True), + ('>=', False, False, True, True, True), + ('==', False, False, True, False, False), + ('!=', True, True, False, True, True), + ): + Equal(compare('1.1', op, '2.2'), less1, op) + Equal(compare('2.1', op, '2.2'), less0, op) + Equal(compare('2.2', op, '2.2'), equal, op) + Equal(compare('2.3', op, '2.2'), greater0, op) + Equal(compare('3.3', op, '2.2'), greater1, op) + + +class MockTextTest(TextTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + from idlelib.idle_test.mock_tk import Text + cls.Text = Text + + def test_decode(self): + # test endflags (-1, 0) not tested by test_index (which uses +1) + decode = self.text._decode + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + Equal(decode('end', -1), (2, 5)) + Equal(decode('3.1', -1), (2, 5)) + Equal(decode('end', 0), (2, 6)) + Equal(decode('3.1', 0), (2, 6)) + + +class TkTextTest(TextTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + from tkinter import Tk, Text + cls.Text = Text + cls.root = Tk() + + @classmethod + def tearDownClass(cls): + cls.root.destroy() + + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 02:19:10 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 02:19:10 +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: <3bsWp61ffHz7LkT@mail.python.org> http://hg.python.org/cpython/rev/979905090779 changeset: 84604:979905090779 parent: 84600:7de05609e390 parent: 84603:8f13fb4c5826 user: Terry Jan Reedy date: Fri Jul 12 20:10:48 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/idle_test/mock_tk.py | 226 ++++++++++++++++- Lib/idlelib/idle_test/test_text.py | 228 +++++++++++++++++ 2 files changed, 449 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py --- a/Lib/idlelib/idle_test/mock_tk.py +++ b/Lib/idlelib/idle_test/mock_tk.py @@ -1,4 +1,5 @@ """Classes that replace tkinter gui objects used by an object being tested. + A gui object is anything with a master or parent paramenter, which is typically required in spite of what the doc strings say. """ @@ -15,8 +16,10 @@ return self.value class Mbox_func: - """Generic mock for messagebox functions. All have same call signature. - Mbox instantiates once for each function. Tester uses attributes. + """Generic mock for messagebox functions, which all have the same signature. + + Instead of displaying a message box, the mock's call method saves the + arguments as instance attributes, which test functions can then examime. """ def __init__(self): self.result = None # The return for all show funcs @@ -30,6 +33,7 @@ class Mbox: """Mock for tkinter.messagebox with an Mbox_func for each function. + This module was 'tkMessageBox' in 2.x; hence the 'import as' in 3.x. Example usage in test_module.py for testing functios in module.py: --- @@ -49,9 +53,9 @@ def tearDownClass(cls): module.tkMessageBox = orig_mbox --- - When tkMessageBox functions are the only gui making calls in a method, - this replacement makes the method gui-free and unit-testable. - For 'ask' functions, set func.result return before calling method. + For 'ask' functions, set func.result return value before calling the method + that uses the message function. When tkMessageBox functions are the + only gui alls in a method, this replacement makes the method gui-free, """ askokcancel = Mbox_func() # True or False askquestion = Mbox_func() # 'yes' or 'no' @@ -61,3 +65,215 @@ showerror = Mbox_func() # None showinfo = Mbox_func() # None showwarning = Mbox_func() # None + +from _tkinter import TclError + +class Text: + """A semi-functional non-gui replacement for tkinter.Text text editors. + + The mock's data model is that a text is a list of \n-terminated lines. + The mock adds an empty string at the beginning of the list so that the + index of actual lines start at 1, as with Tk. The methods never see this. + Tk initializes files with a terminal \n that cannot be deleted. It is + invisible in the sense that one cannot move the cursor beyond it. + + This class is only tested (and valid) with strings of ascii chars. + For testing, we are not concerned with Tk Text's treatment of, + for instance, 0-width characters or character + accent. + """ + def __init__(self, master=None, cnf={}, **kw): + '''Initialize mock, non-gui, text-only Text widget. + + At present, all args are ignored. Almost all affect visual behavior. + There are just a few Text-only options that affect text behavior. + ''' + self.data = ['', '\n'] + + def index(self, index): + "Return string version of index decoded according to current text." + return "%s.%s" % self._decode(index, endflag=1) + + def _decode(self, index, endflag=0): + """Return a (line, char) tuple of int indexes into self.data. + + This implements .index without converting the result back to a string. + The result is contrained by the number of lines and linelengths of + self.data. For many indexes, the result is initally (1, 0). + + The input index may have any of several possible forms: + * line.char float: converted to 'line.char' string; + * 'line.char' string, where line and char are decimal integers; + * 'line.char lineend', where lineend='lineend' (and char is ignored); + * 'line.end', where end='end' (same as above); + * 'insert', the positions before terminal \n; + * 'end', whose meaning depends on the endflag passed to ._endex. + * 'sel.first' or 'sel.last', where sel is a tag -- not implemented. + """ + if isinstance(index, (float, bytes)): + index = str(index) + try: + index=index.lower() + except AttributeError: + raise TclError('bad text index "%s"' % index) from None + + lastline = len(self.data) - 1 # same as number of text lines + if index == 'insert': + return lastline, len(self.data[lastline]) - 1 + elif index == 'end': + return self._endex(endflag) + + line, char = index.split('.') + line = int(line) + + # Out of bounds line becomes first or last ('end') index + if line < 1: + return 1, 0 + elif line > lastline: + return self._endex(endflag) + + linelength = len(self.data[line]) -1 # position before/at \n + if char.endswith(' lineend') or char == 'end': + return line, linelength + # Tk requires that ignored chars before ' lineend' be valid int + + # Out of bounds char becomes first or last index of line + char = int(char) + if char < 0: + char = 0 + elif char > linelength: + char = linelength + return line, char + + def _endex(self, endflag): + '''Return position for 'end' or line overflow corresponding to endflag. + + -1: position before terminal \n; for .insert(), .delete + 0: position after terminal \n; for .get, .delete index 1 + 1: same viewed as begininning of non-existent next line (for .index) + ''' + n = len(self.data) + if endflag == 1: + return n, 0 + else: + n -= 1 + return n, len(self.data[n]) + endflag + + + def insert(self, index, chars): + "Insert chars before the character at index." + + if not chars: # ''.splitlines() is [], not [''] + return + chars = chars.splitlines(True) + if chars[-1][-1] == '\n': + chars.append('') + line, char = self._decode(index, -1) + before = self.data[line][:char] + after = self.data[line][char:] + self.data[line] = before + chars[0] + self.data[line+1:line+1] = chars[1:] + self.data[line+len(chars)-1] += after + + + def get(self, index1, index2=None): + "Return slice from index1 to index2 (default is 'index1+1')." + + startline, startchar = self._decode(index1) + if index2 is None: + endline, endchar = startline, startchar+1 + else: + endline, endchar = self._decode(index2) + + if startline == endline: + return self.data[startline][startchar:endchar] + else: + lines = [self.data[startline][startchar:]] + for i in range(startline+1, endline): + lines.append(self.data[i]) + lines.append(self.data[endline][:endchar]) + return ''.join(lines) + + + def delete(self, index1, index2=None): + '''Delete slice from index1 to index2 (default is 'index1+1'). + + Adjust default index2 ('index+1) for line ends. + Do not delete the terminal \n at the very end of self.data ([-1][-1]). + ''' + startline, startchar = self._decode(index1, -1) + if index2 is None: + if startchar < len(self.data[startline])-1: + # not deleting \n + endline, endchar = startline, startchar+1 + elif startline < len(self.data) - 1: + # deleting non-terminal \n, convert 'index1+1 to start of next line + endline, endchar = startline+1, 0 + else: + # do not delete terminal \n if index1 == 'insert' + return + else: + endline, endchar = self._decode(index2, -1) + # restricting end position to insert position excludes terminal \n + + if startline == endline and startchar < endchar: + self.data[startline] = self.data[startline][:startchar] + \ + self.data[startline][endchar:] + elif startline < endline: + self.data[startline] = self.data[startline][:startchar] + \ + self.data[endline][endchar:] + startline += 1 + for i in range(startline, endline+1): + del self.data[startline] + + def compare(self, index1, op, index2): + line1, char1 = self._decode(index1) + line2, char2 = self._decode(index2) + if op == '<': + return line1 < line2 or line1 == line2 and char1 < char2 + elif op == '<=': + return line1 < line2 or line1 == line2 and char1 <= char2 + elif op == '>': + return line1 > line2 or line1 == line2 and char1 > char2 + elif op == '>=': + return line1 > line2 or line1 == line2 and char1 >= char2 + elif op == '==': + return line1 == line2 and char1 == char2 + elif op == '!=': + return line1 != line2 or char1 != char2 + else: + raise TclError('''bad comparison operator "%s":''' + '''must be <, <=, ==, >=, >, or !=''' % op) + + # The following Text methods normally do something and return None. + # Whether doing nothing is sufficient for a test will depend on the test. + + def mark_set(self, name, index): + "Set mark *name* before the character at index." + pass + + def mark_unset(self, *markNames): + "Delete all marks in markNames." + + def tag_remove(self, tagName, index1, index2=None): + "Remove tag tagName from all characters between index1 and index2." + pass + + # The following Text methods affect the graphics screen and return None. + # Doing nothing should always be sufficient for tests. + + def scan_dragto(self, x, y): + "Adjust the view of the text according to scan_mark" + + def scan_mark(self, x, y): + "Remember the current X, Y coordinates." + + def see(self, index): + "Scroll screen to make the character at INDEX is visible." + pass + + # The following is a Misc method inheritet by Text. + # It should properly go in a Misc mock, but is included here for now. + + def bind(sequence=None, func=None, add=None): + "Bind to this widget at event sequence a call to function func." + pass diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_text.py @@ -0,0 +1,228 @@ +# Test mock_tk.Text class against tkinter.Text class by running same tests with both. +import unittest +from test.support import requires + +from _tkinter import TclError +import tkinter as tk + +class TextTest(object): + + hw = 'hello\nworld' # usual initial insert after initialization + hwn = hw+'\n' # \n present at initialization, before insert + + Text = None + def setUp(self): + self.text = self.Text() + + def test_init(self): + self.assertEqual(self.text.get('1.0'), '\n') + self.assertEqual(self.text.get('end'), '') + + def test_index_empty(self): + index = self.text.index + + for dex in (-1.0, 0.3, '1.-1', '1.0', '1.0 lineend', '1.end', '1.33', + 'insert'): + self.assertEqual(index(dex), '1.0') + + for dex in 'end', 2.0, '2.1', '33.44': + self.assertEqual(index(dex), '2.0') + + def test_index_data(self): + index = self.text.index + self.text.insert('1.0', self.hw) + + for dex in -1.0, 0.3, '1.-1', '1.0': + self.assertEqual(index(dex), '1.0') + + for dex in '1.0 lineend', '1.end', '1.33': + self.assertEqual(index(dex), '1.5') + + for dex in 'end', '33.44': + self.assertEqual(index(dex), '3.0') + + def test_get(self): + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + Equal(get('end'), '') + Equal(get('end', 'end'), '') + Equal(get('1.0'), 'h') + Equal(get('1.0', '1.1'), 'h') + Equal(get('1.0', '1.3'), 'hel') + Equal(get('1.1', '1.3'), 'el') + Equal(get('1.0', '1.0 lineend'), 'hello') + Equal(get('1.0', '1.10'), 'hello') + Equal(get('1.0 lineend'), '\n') + Equal(get('1.1', '2.3'), 'ello\nwor') + Equal(get('1.0', '2.5'), self.hw) + Equal(get('1.0', 'end'), self.hwn) + Equal(get('0.0', '5.0'), self.hwn) + + def test_insert(self): + insert = self.text.insert + get = self.text.get + Equal = self.assertEqual + + insert('1.0', self.hw) + Equal(get('1.0', 'end'), self.hwn) + + insert('1.0', '') # nothing + Equal(get('1.0', 'end'), self.hwn) + + insert('1.0', '*') + Equal(get('1.0', 'end'), '*hello\nworld\n') + + insert('1.0 lineend', '*') + Equal(get('1.0', 'end'), '*hello*\nworld\n') + + insert('2.3', '*') + Equal(get('1.0', 'end'), '*hello*\nwor*ld\n') + + insert('end', 'x') + Equal(get('1.0', 'end'), '*hello*\nwor*ldx\n') + + insert('1.4', 'x\n') + Equal(get('1.0', 'end'), '*helx\nlo*\nwor*ldx\n') + + def test_no_delete(self): + # if index1 == 'insert' or 'end' or >= end, there is no deletion + delete = self.text.delete + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + delete('insert') + Equal(get('1.0', 'end'), self.hwn) + + delete('end') + Equal(get('1.0', 'end'), self.hwn) + + delete('insert', 'end') + Equal(get('1.0', 'end'), self.hwn) + + delete('insert', '5.5') + Equal(get('1.0', 'end'), self.hwn) + + delete('1.4', '1.0') + Equal(get('1.0', 'end'), self.hwn) + + delete('1.4', '1.4') + Equal(get('1.0', 'end'), self.hwn) + + def test_delete_char(self): + delete = self.text.delete + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + delete('1.0') + Equal(get('1.0', '1.end'), 'ello') + + delete('1.0', '1.1') + Equal(get('1.0', '1.end'), 'llo') + + # delete \n and combine 2 lines into 1 + delete('1.end') + Equal(get('1.0', '1.end'), 'lloworld') + + self.text.insert('1.3', '\n') + delete('1.10') + Equal(get('1.0', '1.end'), 'lloworld') + + self.text.insert('1.3', '\n') + delete('1.3', '2.0') + Equal(get('1.0', '1.end'), 'lloworld') + + def test_delete_slice(self): + delete = self.text.delete + get = self.text.get + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + delete('1.0', '1.0 lineend') + Equal(get('1.0', 'end'), '\nworld\n') + + delete('1.0', 'end') + Equal(get('1.0', 'end'), '\n') + + self.text.insert('1.0', self.hw) + delete('1.0', '2.0') + Equal(get('1.0', 'end'), 'world\n') + + delete('1.0', 'end') + Equal(get('1.0', 'end'), '\n') + + self.text.insert('1.0', self.hw) + delete('1.2', '2.3') + Equal(get('1.0', 'end'), 'held\n') + + def test_multiple_lines(self): # insert and delete + self.text.insert('1.0', 'hello') + + self.text.insert('1.3', '1\n2\n3\n4\n5') + self.assertEqual(self.text.get('1.0', 'end'), 'hel1\n2\n3\n4\n5lo\n') + + self.text.delete('1.3', '5.1') + self.assertEqual(self.text.get('1.0', 'end'), 'hello\n') + + def test_compare(self): + compare = self.text.compare + Equal = self.assertEqual + # need data so indexes not squished to 1,0 + self.text.insert('1.0', 'First\nSecond\nThird\n') + + self.assertRaises(TclError, compare, '2.2', 'op', '2.2') + + for op, less1, less0, equal, greater0, greater1 in ( + ('<', True, True, False, False, False), + ('<=', True, True, True, False, False), + ('>', False, False, False, True, True), + ('>=', False, False, True, True, True), + ('==', False, False, True, False, False), + ('!=', True, True, False, True, True), + ): + Equal(compare('1.1', op, '2.2'), less1, op) + Equal(compare('2.1', op, '2.2'), less0, op) + Equal(compare('2.2', op, '2.2'), equal, op) + Equal(compare('2.3', op, '2.2'), greater0, op) + Equal(compare('3.3', op, '2.2'), greater1, op) + + +class MockTextTest(TextTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + from idlelib.idle_test.mock_tk import Text + cls.Text = Text + + def test_decode(self): + # test endflags (-1, 0) not tested by test_index (which uses +1) + decode = self.text._decode + Equal = self.assertEqual + self.text.insert('1.0', self.hw) + + Equal(decode('end', -1), (2, 5)) + Equal(decode('3.1', -1), (2, 5)) + Equal(decode('end', 0), (2, 6)) + Equal(decode('3.1', 0), (2, 6)) + + +class TkTextTest(TextTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + from tkinter import Tk, Text + cls.Text = Text + cls.root = Tk() + + @classmethod + def tearDownClass(cls): + cls.root.destroy() + + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 02:19:11 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 02:19:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzY1?= =?utf-8?q?=3A_normalize_whitespace?= Message-ID: <3bsWp73MlTz7Lkv@mail.python.org> http://hg.python.org/cpython/rev/5611d3a954f8 changeset: 84605:5611d3a954f8 branch: 3.3 parent: 84603:8f13fb4c5826 user: Terry Jan Reedy date: Fri Jul 12 20:16:28 2013 -0400 summary: Issue #18365: normalize whitespace files: Lib/idlelib/idle_test/mock_tk.py | 12 ++++++------ Lib/idlelib/idle_test/test_text.py | 3 +-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py --- a/Lib/idlelib/idle_test/mock_tk.py +++ b/Lib/idlelib/idle_test/mock_tk.py @@ -210,7 +210,7 @@ endline, endchar = startline+1, 0 else: # do not delete terminal \n if index1 == 'insert' - return + return else: endline, endchar = self._decode(index2, -1) # restricting end position to insert position excludes terminal \n @@ -219,11 +219,11 @@ self.data[startline] = self.data[startline][:startchar] + \ self.data[startline][endchar:] elif startline < endline: - self.data[startline] = self.data[startline][:startchar] + \ - self.data[endline][endchar:] - startline += 1 - for i in range(startline, endline+1): - del self.data[startline] + self.data[startline] = self.data[startline][:startchar] + \ + self.data[endline][endchar:] + startline += 1 + for i in range(startline, endline+1): + del self.data[startline] def compare(self, index1, op, index2): line1, char1 = self._decode(index1) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -36,7 +36,7 @@ self.assertEqual(index(dex), '1.0') for dex in '1.0 lineend', '1.end', '1.33': - self.assertEqual(index(dex), '1.5') + self.assertEqual(index(dex), '1.5') for dex in 'end', '33.44': self.assertEqual(index(dex), '3.0') @@ -225,4 +225,3 @@ if __name__ == '__main__': unittest.main(verbosity=2, exit=False) - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 02:19:12 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 02:19: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: <3bsWp85BqWz7LkQ@mail.python.org> http://hg.python.org/cpython/rev/514cb18945aa changeset: 84606:514cb18945aa parent: 84604:979905090779 parent: 84605:5611d3a954f8 user: Terry Jan Reedy date: Fri Jul 12 20:17:00 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/idle_test/mock_tk.py | 12 ++++++------ Lib/idlelib/idle_test/test_text.py | 3 +-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py --- a/Lib/idlelib/idle_test/mock_tk.py +++ b/Lib/idlelib/idle_test/mock_tk.py @@ -210,7 +210,7 @@ endline, endchar = startline+1, 0 else: # do not delete terminal \n if index1 == 'insert' - return + return else: endline, endchar = self._decode(index2, -1) # restricting end position to insert position excludes terminal \n @@ -219,11 +219,11 @@ self.data[startline] = self.data[startline][:startchar] + \ self.data[startline][endchar:] elif startline < endline: - self.data[startline] = self.data[startline][:startchar] + \ - self.data[endline][endchar:] - startline += 1 - for i in range(startline, endline+1): - del self.data[startline] + self.data[startline] = self.data[startline][:startchar] + \ + self.data[endline][endchar:] + startline += 1 + for i in range(startline, endline+1): + del self.data[startline] def compare(self, index1, op, index2): line1, char1 = self._decode(index1) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -36,7 +36,7 @@ self.assertEqual(index(dex), '1.0') for dex in '1.0 lineend', '1.end', '1.33': - self.assertEqual(index(dex), '1.5') + self.assertEqual(index(dex), '1.5') for dex in 'end', '33.44': self.assertEqual(index(dex), '3.0') @@ -225,4 +225,3 @@ if __name__ == '__main__': unittest.main(verbosity=2, exit=False) - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 02:19:14 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 02:19:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MzY1?= =?utf-8?q?=3A_normalize_whitespace?= Message-ID: <3bsWpB0Dw8z7LkW@mail.python.org> http://hg.python.org/cpython/rev/86cc1983a94d changeset: 84607:86cc1983a94d branch: 2.7 parent: 84602:5ac2ec0a34a5 user: Terry Jan Reedy date: Fri Jul 12 20:18:33 2013 -0400 summary: Issue #18365: normalize whitespace files: Lib/idlelib/idle_test/mock_tk.py | 12 ++++++------ Lib/idlelib/idle_test/test_text.py | 3 +-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py --- a/Lib/idlelib/idle_test/mock_tk.py +++ b/Lib/idlelib/idle_test/mock_tk.py @@ -210,7 +210,7 @@ endline, endchar = startline+1, 0 else: # do not delete terminal \n if index1 == 'insert' - return + return else: endline, endchar = self._decode(index2, -1) # restricting end position to insert position excludes terminal \n @@ -219,11 +219,11 @@ self.data[startline] = self.data[startline][:startchar] + \ self.data[startline][endchar:] elif startline < endline: - self.data[startline] = self.data[startline][:startchar] + \ - self.data[endline][endchar:] - startline += 1 - for i in range(startline, endline+1): - del self.data[startline] + self.data[startline] = self.data[startline][:startchar] + \ + self.data[endline][endchar:] + startline += 1 + for i in range(startline, endline+1): + del self.data[startline] def compare(self, index1, op, index2): line1, char1 = self._decode(index1) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -36,7 +36,7 @@ self.assertEqual(index(dex), '1.0') for dex in '1.0 lineend', '1.end', '1.33': - self.assertEqual(index(dex), '1.5') + self.assertEqual(index(dex), '1.5') for dex in 'end', '33.44': self.assertEqual(index(dex), '3.0') @@ -225,4 +225,3 @@ if __name__ == '__main__': unittest.main(verbosity=2, exit=False) - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 04:57:26 2013 From: python-checkins at python.org (r.david.murray) Date: Sat, 13 Jul 2013 04:57:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4NDM3OiBmaXgg?= =?utf-8?q?comment_typo=2E?= Message-ID: <3bsbJk4slXz7Ljp@mail.python.org> http://hg.python.org/cpython/rev/f91e6d0eb0f7 changeset: 84608:f91e6d0eb0f7 branch: 3.3 parent: 84605:5611d3a954f8 user: R David Murray date: Fri Jul 12 22:55:43 2013 -0400 summary: #18437: fix comment typo. files: Lib/email/charset.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/email/charset.py b/Lib/email/charset.py --- a/Lib/email/charset.py +++ b/Lib/email/charset.py @@ -194,7 +194,7 @@ header encoding. Charset.SHORTEST is not allowed for body_encoding. - output_charset: Some character sets must be converted before the can be + output_charset: Some character sets must be converted before they can be used in email headers or bodies. If the input_charset is one of them, this attribute will contain the name of the charset output will be converted to. Otherwise, it will -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 04:57:27 2013 From: python-checkins at python.org (r.david.murray) Date: Sat, 13 Jul 2013 04:57:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_=2318437=3A_fix_comment_typo=2E?= Message-ID: <3bsbJl6fyzz7Lk9@mail.python.org> http://hg.python.org/cpython/rev/da7d97ca1ef6 changeset: 84609:da7d97ca1ef6 parent: 84606:514cb18945aa parent: 84608:f91e6d0eb0f7 user: R David Murray date: Fri Jul 12 22:56:15 2013 -0400 summary: Merge: #18437: fix comment typo. files: Lib/email/charset.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/email/charset.py b/Lib/email/charset.py --- a/Lib/email/charset.py +++ b/Lib/email/charset.py @@ -194,7 +194,7 @@ header encoding. Charset.SHORTEST is not allowed for body_encoding. - output_charset: Some character sets must be converted before the can be + output_charset: Some character sets must be converted before they can be used in email headers or bodies. If the input_charset is one of them, this attribute will contain the name of the charset output will be converted to. Otherwise, it will -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 04:57:29 2013 From: python-checkins at python.org (r.david.murray) Date: Sat, 13 Jul 2013 04:57:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE4NDM3OiBmaXgg?= =?utf-8?q?comment_typo=2E?= Message-ID: <3bsbJn1NkKz7Ll7@mail.python.org> http://hg.python.org/cpython/rev/868010ed641c changeset: 84610:868010ed641c branch: 2.7 parent: 84607:86cc1983a94d user: R David Murray date: Fri Jul 12 22:57:12 2013 -0400 summary: #18437: fix comment typo. files: Lib/email/charset.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/email/charset.py b/Lib/email/charset.py --- a/Lib/email/charset.py +++ b/Lib/email/charset.py @@ -183,7 +183,7 @@ header encoding. Charset.SHORTEST is not allowed for body_encoding. - output_charset: Some character sets must be converted before the can be + output_charset: Some character sets must be converted before they can be used in email headers or bodies. If the input_charset is one of them, this attribute will contain the name of the charset output will be converted to. Otherwise, it will -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jul 13 05:47:33 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 13 Jul 2013 05:47:33 +0200 Subject: [Python-checkins] Daily reference leaks (514cb18945aa): sum=-1 Message-ID: results for 514cb18945aa 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/reflogrV5UAp', '-x'] From python-checkins at python.org Sat Jul 13 06:02:46 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 06:02:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MzY1?= =?utf-8?q?=3A_2=2E7_corrections_so_tests_run?= Message-ID: <3bscm65tyTz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/008d83c4efaf changeset: 84611:008d83c4efaf branch: 2.7 user: Terry Jan Reedy date: Sat Jul 13 00:02:27 2013 -0400 summary: Issue #18365: 2.7 corrections so tests run files: Lib/idlelib/idle_test/mock_tk.py | 2 +- Lib/idlelib/idle_test/test_text.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py --- a/Lib/idlelib/idle_test/mock_tk.py +++ b/Lib/idlelib/idle_test/mock_tk.py @@ -114,7 +114,7 @@ try: index=index.lower() except AttributeError: - raise TclError('bad text index "%s"' % index) from None + raise TclError('bad text index "%s"' % index) lastline = len(self.data) - 1 # same as number of text lines if index == 'insert': diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -1,9 +1,9 @@ # Test mock_tk.Text class against tkinter.Text class by running same tests with both. import unittest -from test.support import requires +from test.test_support import requires from _tkinter import TclError -import tkinter as tk +import Tkinter as tk class TextTest(object): @@ -214,7 +214,7 @@ @classmethod def setUpClass(cls): requires('gui') - from tkinter import Tk, Text + from Tkinter import Tk, Text cls.Text = Text cls.root = Tk() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 08:35:34 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 08:35:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4Mjc5?= =?utf-8?q?=3A_Add_tests_for_idlelib/RstripExtension=2Epy=2E_Original_patc?= =?utf-8?q?h_by?= Message-ID: <3bsh8Q5MrTz7LkS@mail.python.org> http://hg.python.org/cpython/rev/ec71fcdcfeac changeset: 84612:ec71fcdcfeac branch: 2.7 user: Terry Jan Reedy date: Sat Jul 13 02:34:35 2013 -0400 summary: Issue #18279: Add tests for idlelib/RstripExtension.py. Original patch by Phil Webster. With that available, modify RstripExtension.py to stop deleting null slices, which caused a file to be marked as changed when it was not. files: Lib/idlelib/RstripExtension.py | 20 +++-- Lib/idlelib/idle_test/mock_idle.py | 27 ++++++++ Lib/idlelib/idle_test/test_rstrip.py | 49 ++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 5 + 5 files changed, 94 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/RstripExtension.py b/Lib/idlelib/RstripExtension.py --- a/Lib/idlelib/RstripExtension.py +++ b/Lib/idlelib/RstripExtension.py @@ -1,13 +1,9 @@ 'Provides "Strip trailing whitespace" under the "Format" menu.' -__author__ = "Roger D. Serwy " - class RstripExtension: menudefs = [ - ('format', [None, - ('Strip trailing whitespace', '<>'), - ]),] + ('format', [None, ('Strip trailing whitespace', '<>'), ] ), ] def __init__(self, editwin): self.editwin = editwin @@ -20,10 +16,18 @@ undo.undo_block_start() - end_line = int(float(text.index('end'))) + 1 + end_line = int(float(text.index('end'))) for cur in range(1, end_line): - txt = text.get('%i.0' % cur, '%i.0 lineend' % cur) + txt = text.get('%i.0' % cur, '%i.end' % cur) + raw = len(txt) cut = len(txt.rstrip()) - text.delete('%i.%i' % (cur, cut), '%i.0 lineend' % cur) + # Since text.delete() marks file as changed, even if not, + # only call it when needed to actually delete something. + if cut < raw: + text.delete('%i.%i' % (cur, cut), '%i.end' % cur) undo.undo_block_stop() + +if __name__ == "__main__": + import unittest + unittest.main('idlelib.idle_test.test_rstrip', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/mock_idle.py b/Lib/idlelib/idle_test/mock_idle.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/mock_idle.py @@ -0,0 +1,27 @@ +'''Mock classes that imitate idlelib modules or classes. + +Attributes and methods will be added as needed for tests. +''' + +from idlelib.idle_test.mock_tk import Text + +class Editor(object): + '''Minimally imitate EditorWindow.EditorWindow class. + ''' + def __init__(self, flist=None, filename=None, key=None, root=None): + self.text = Text() + self.undo = UndoDelegator() + + def get_selection_indices(self): + first = self.text.index('1.0') + last = self.text.index('end') + return first, last + +class UndoDelegator(object): + '''Minimally imitate UndoDelegator,UndoDelegator class. + ''' + # A real undo block is only needed for user interaction. + def undo_block_start(*args): + pass + def undo_block_stop(*args): + pass diff --git a/Lib/idlelib/idle_test/test_rstrip.py b/Lib/idlelib/idle_test/test_rstrip.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_rstrip.py @@ -0,0 +1,49 @@ +import unittest +import idlelib.RstripExtension as rs +from idlelib.idle_test.mock_idle import Editor + +class rstripTest(unittest.TestCase): + + def test_rstrip_line(self): + editor = Editor() + text = editor.text + do_rstrip = rs.RstripExtension(editor).do_rstrip + + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), '') + text.insert('1.0', ' ') + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), '') + text.insert('1.0', ' \n') + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), '\n') + + def test_rstrip_multiple(self): + editor = Editor() + # Uncomment following to verify that test passes with real widgets. +## from idlelib.EditorWindow import EditorWindow as Editor +## from tkinter import Tk +## editor = Editor(root=Tk()) + text = editor.text + do_rstrip = rs.RstripExtension(editor).do_rstrip + + original = ( + "Line with an ending tab \n" + "Line ending in 5 spaces \n" + "Linewithnospaces\n" + " indented line\n" + " indented line with trailing space \n" + " ") + stripped = ( + "Line with an ending tab\n" + "Line ending in 5 spaces\n" + "Linewithnospaces\n" + " indented line\n" + " indented line with trailing space\n") + + text.insert('1.0', original) + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), stripped) + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1083,6 +1083,7 @@ Henrik Weber Corran Webster Glyn Webster +Phil Webster Stefan Wehr Zack Weinberg Bob Weiner diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -91,6 +91,10 @@ IDLE ---- +- Issue #18279: Format - Strip trailing whitespace no longer marks a file as + changed when it has not been changed. This fix followed the addition of a + test file originally written by Phil Webster (the issue's main goal). + - Issue #7136: In the Idle File menu, "New Window" is renamed "New File". Patch by Tal Einat, Roget Serwy, and Todd Rovito. @@ -104,6 +108,7 @@ - Issue #15392: Create a unittest framework for IDLE. Preliminary patch by Rajagopalasarma Jayakrishnan + See Lib/idlelib/idle_test/README.txt for how to run Idle tests. - Issue #14146: Highlight source line while debugging on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 08:35:36 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 08:35:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4Mjc5?= =?utf-8?q?=3A_Add_tests_for_idlelib/RstripExtension=2Epy=2E_Original_patc?= =?utf-8?q?h_by?= Message-ID: <3bsh8S1Lyyz7Llr@mail.python.org> http://hg.python.org/cpython/rev/22ce68d98345 changeset: 84613:22ce68d98345 branch: 3.3 parent: 84608:f91e6d0eb0f7 user: Terry Jan Reedy date: Sat Jul 13 02:34:43 2013 -0400 summary: Issue #18279: Add tests for idlelib/RstripExtension.py. Original patch by Phil Webster. With that available, modify RstripExtension.py to stop deleting null slices, which caused a file to be marked as changed when it was not. files: Lib/idlelib/RstripExtension.py | 20 +++-- Lib/idlelib/idle_test/mock_idle.py | 27 ++++++++ Lib/idlelib/idle_test/test_rstrip.py | 49 ++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 5 + 5 files changed, 94 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/RstripExtension.py b/Lib/idlelib/RstripExtension.py --- a/Lib/idlelib/RstripExtension.py +++ b/Lib/idlelib/RstripExtension.py @@ -1,13 +1,9 @@ 'Provides "Strip trailing whitespace" under the "Format" menu.' -__author__ = "Roger D. Serwy " - class RstripExtension: menudefs = [ - ('format', [None, - ('Strip trailing whitespace', '<>'), - ]),] + ('format', [None, ('Strip trailing whitespace', '<>'), ] ), ] def __init__(self, editwin): self.editwin = editwin @@ -20,10 +16,18 @@ undo.undo_block_start() - end_line = int(float(text.index('end'))) + 1 + end_line = int(float(text.index('end'))) for cur in range(1, end_line): - txt = text.get('%i.0' % cur, '%i.0 lineend' % cur) + txt = text.get('%i.0' % cur, '%i.end' % cur) + raw = len(txt) cut = len(txt.rstrip()) - text.delete('%i.%i' % (cur, cut), '%i.0 lineend' % cur) + # Since text.delete() marks file as changed, even if not, + # only call it when needed to actually delete something. + if cut < raw: + text.delete('%i.%i' % (cur, cut), '%i.end' % cur) undo.undo_block_stop() + +if __name__ == "__main__": + import unittest + unittest.main('idlelib.idle_test.test_rstrip', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/mock_idle.py b/Lib/idlelib/idle_test/mock_idle.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/mock_idle.py @@ -0,0 +1,27 @@ +'''Mock classes that imitate idlelib modules or classes. + +Attributes and methods will be added as needed for tests. +''' + +from idlelib.idle_test.mock_tk import Text + +class Editor: + '''Minimally imitate EditorWindow.EditorWindow class. + ''' + def __init__(self, flist=None, filename=None, key=None, root=None): + self.text = Text() + self.undo = UndoDelegator() + + def get_selection_indices(self): + first = self.text.index('1.0') + last = self.text.index('end') + return first, last + +class UndoDelegator: + '''Minimally imitate UndoDelegator,UndoDelegator class. + ''' + # A real undo block is only needed for user interaction. + def undo_block_start(*args): + pass + def undo_block_stop(*args): + pass diff --git a/Lib/idlelib/idle_test/test_rstrip.py b/Lib/idlelib/idle_test/test_rstrip.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_rstrip.py @@ -0,0 +1,49 @@ +import unittest +import idlelib.RstripExtension as rs +from idlelib.idle_test.mock_idle import Editor + +class rstripTest(unittest.TestCase): + + def test_rstrip_line(self): + editor = Editor() + text = editor.text + do_rstrip = rs.RstripExtension(editor).do_rstrip + + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), '') + text.insert('1.0', ' ') + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), '') + text.insert('1.0', ' \n') + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), '\n') + + def test_rstrip_multiple(self): + editor = Editor() + # Uncomment following to verify that test passes with real widgets. +## from idlelib.EditorWindow import EditorWindow as Editor +## from tkinter import Tk +## editor = Editor(root=Tk()) + text = editor.text + do_rstrip = rs.RstripExtension(editor).do_rstrip + + original = ( + "Line with an ending tab \n" + "Line ending in 5 spaces \n" + "Linewithnospaces\n" + " indented line\n" + " indented line with trailing space \n" + " ") + stripped = ( + "Line with an ending tab\n" + "Line ending in 5 spaces\n" + "Linewithnospaces\n" + " indented line\n" + " indented line with trailing space\n") + + text.insert('1.0', original) + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), stripped) + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1303,6 +1303,7 @@ Henrik Weber Corran Webster Glyn Webster +Phil Webster Stefan Wehr Zack Weinberg Bob Weiner diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -160,6 +160,10 @@ IDLE ---- +- Issue #18279: Format - Strip trailing whitespace no longer marks a file as + changed when it has not been changed. This fix followed the addition of a + test file originally written by Phil Webster (the issue's main goal). + - Issue #7136: In the Idle File menu, "New Window" is renamed "New File". Patch by Tal Einat, Roget Serwy, and Todd Rovito. @@ -176,6 +180,7 @@ - Issue #15392: Create a unittest framework for IDLE. Initial patch by Rajagopalasarma Jayakrishnan. + See Lib/idlelib/idle_test/README.txt for how to run Idle tests. - Issue #14146: Highlight source line while debugging on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 08:35:37 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 08:35:37 +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: <3bsh8T4Xf8z7LjM@mail.python.org> http://hg.python.org/cpython/rev/ffd923b388d8 changeset: 84614:ffd923b388d8 parent: 84609:da7d97ca1ef6 parent: 84613:22ce68d98345 user: Terry Jan Reedy date: Sat Jul 13 02:35:07 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/RstripExtension.py | 20 +++-- Lib/idlelib/idle_test/mock_idle.py | 27 ++++++++ Lib/idlelib/idle_test/test_rstrip.py | 49 ++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 5 + 5 files changed, 94 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/RstripExtension.py b/Lib/idlelib/RstripExtension.py --- a/Lib/idlelib/RstripExtension.py +++ b/Lib/idlelib/RstripExtension.py @@ -1,13 +1,9 @@ 'Provides "Strip trailing whitespace" under the "Format" menu.' -__author__ = "Roger D. Serwy " - class RstripExtension: menudefs = [ - ('format', [None, - ('Strip trailing whitespace', '<>'), - ]),] + ('format', [None, ('Strip trailing whitespace', '<>'), ] ), ] def __init__(self, editwin): self.editwin = editwin @@ -20,10 +16,18 @@ undo.undo_block_start() - end_line = int(float(text.index('end'))) + 1 + end_line = int(float(text.index('end'))) for cur in range(1, end_line): - txt = text.get('%i.0' % cur, '%i.0 lineend' % cur) + txt = text.get('%i.0' % cur, '%i.end' % cur) + raw = len(txt) cut = len(txt.rstrip()) - text.delete('%i.%i' % (cur, cut), '%i.0 lineend' % cur) + # Since text.delete() marks file as changed, even if not, + # only call it when needed to actually delete something. + if cut < raw: + text.delete('%i.%i' % (cur, cut), '%i.end' % cur) undo.undo_block_stop() + +if __name__ == "__main__": + import unittest + unittest.main('idlelib.idle_test.test_rstrip', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/mock_idle.py b/Lib/idlelib/idle_test/mock_idle.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/mock_idle.py @@ -0,0 +1,27 @@ +'''Mock classes that imitate idlelib modules or classes. + +Attributes and methods will be added as needed for tests. +''' + +from idlelib.idle_test.mock_tk import Text + +class Editor: + '''Minimally imitate EditorWindow.EditorWindow class. + ''' + def __init__(self, flist=None, filename=None, key=None, root=None): + self.text = Text() + self.undo = UndoDelegator() + + def get_selection_indices(self): + first = self.text.index('1.0') + last = self.text.index('end') + return first, last + +class UndoDelegator: + '''Minimally imitate UndoDelegator,UndoDelegator class. + ''' + # A real undo block is only needed for user interaction. + def undo_block_start(*args): + pass + def undo_block_stop(*args): + pass diff --git a/Lib/idlelib/idle_test/test_rstrip.py b/Lib/idlelib/idle_test/test_rstrip.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_rstrip.py @@ -0,0 +1,49 @@ +import unittest +import idlelib.RstripExtension as rs +from idlelib.idle_test.mock_idle import Editor + +class rstripTest(unittest.TestCase): + + def test_rstrip_line(self): + editor = Editor() + text = editor.text + do_rstrip = rs.RstripExtension(editor).do_rstrip + + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), '') + text.insert('1.0', ' ') + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), '') + text.insert('1.0', ' \n') + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), '\n') + + def test_rstrip_multiple(self): + editor = Editor() + # Uncomment following to verify that test passes with real widgets. +## from idlelib.EditorWindow import EditorWindow as Editor +## from tkinter import Tk +## editor = Editor(root=Tk()) + text = editor.text + do_rstrip = rs.RstripExtension(editor).do_rstrip + + original = ( + "Line with an ending tab \n" + "Line ending in 5 spaces \n" + "Linewithnospaces\n" + " indented line\n" + " indented line with trailing space \n" + " ") + stripped = ( + "Line with an ending tab\n" + "Line ending in 5 spaces\n" + "Linewithnospaces\n" + " indented line\n" + " indented line with trailing space\n") + + text.insert('1.0', original) + do_rstrip() + self.assertEqual(text.get('1.0', 'insert'), stripped) + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1339,6 +1339,7 @@ Henrik Weber Corran Webster Glyn Webster +Phil Webster Stefan Wehr Zack Weinberg Bob Weiner diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -601,6 +601,10 @@ IDLE ---- +- Issue #18279: Format - Strip trailing whitespace no longer marks a file as + changed when it has not been changed. This fix followed the addition of a + test file originally written by Phil Webster (the issue's main goal). + - Issue #7136: In the Idle File menu, "New Window" is renamed "New File". Patch by Tal Einat, Roget Serwy, and Todd Rovito. @@ -617,6 +621,7 @@ - Issue #15392: Create a unittest framework for IDLE. Initial patch by Rajagopalasarma Jayakrishnan. + See Lib/idlelib/idle_test/README.txt for how to run Idle tests. - Issue #14146: Highlight source line while debugging on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 10:07:05 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 10:07:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzY1?= =?utf-8?q?=3A_convert_buildbot_errors_to_skips=2E?= Message-ID: <3bskB109bgz7Lkk@mail.python.org> http://hg.python.org/cpython/rev/bc3a34e47923 changeset: 84615:bc3a34e47923 branch: 3.3 parent: 84613:22ce68d98345 user: Terry Jan Reedy date: Sat Jul 13 04:05:42 2013 -0400 summary: Issue #18365: convert buildbot errors to skips. files: Lib/idlelib/idle_test/test_text.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -216,7 +216,10 @@ requires('gui') from tkinter import Tk, Text cls.Text = Text - cls.root = Tk() + try: + cls.root = Tk() + except TclError as msg: + raise unittest.SkipTest('TclError: %s' % msg) @classmethod def tearDownClass(cls): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 10:07:06 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 10:07:06 +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: <3bskB223R5z7LlD@mail.python.org> http://hg.python.org/cpython/rev/f478eb9adfe0 changeset: 84616:f478eb9adfe0 parent: 84614:ffd923b388d8 parent: 84615:bc3a34e47923 user: Terry Jan Reedy date: Sat Jul 13 04:06:03 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/idle_test/test_text.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -216,7 +216,10 @@ requires('gui') from tkinter import Tk, Text cls.Text = Text - cls.root = Tk() + try: + cls.root = Tk() + except TclError as msg: + raise unittest.SkipTest('TclError: %s' % msg) @classmethod def tearDownClass(cls): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 10:07:07 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 13 Jul 2013 10:07:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MzY1?= =?utf-8?q?=3A_convert_buildbot_errors_to_skips=2E?= Message-ID: <3bskB33ty9z7LmN@mail.python.org> http://hg.python.org/cpython/rev/ba4c826848d5 changeset: 84617:ba4c826848d5 branch: 2.7 parent: 84612:ec71fcdcfeac user: Terry Jan Reedy date: Sat Jul 13 04:05:42 2013 -0400 summary: Issue #18365: convert buildbot errors to skips. files: Lib/idlelib/idle_test/test_text.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -216,7 +216,10 @@ requires('gui') from Tkinter import Tk, Text cls.Text = Text - cls.root = Tk() + try: + cls.root = Tk() + except TclError as msg: + raise unittest.SkipTest('TclError: %s' % msg) @classmethod def tearDownClass(cls): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 13 11:34:19 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 13 Jul 2013 11:34:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_the_freeblock=28=29_c?= =?utf-8?q?all_outside_the_main_loop_to_speed-up_and_simplify_the?= Message-ID: <3bsm6g4BgZz7LkS@mail.python.org> http://hg.python.org/cpython/rev/6a3a613f1335 changeset: 84618:6a3a613f1335 parent: 84616:f478eb9adfe0 user: Raymond Hettinger date: Sat Jul 13 02:34:08 2013 -0700 summary: Move the freeblock() call outside the main loop to speed-up and simplify the block re-use logic. files: Modules/_collectionsmodule.c | 24 +++++++++++++++--------- 1 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -454,12 +454,13 @@ static int _deque_rotate(dequeobject *deque, Py_ssize_t n) { + block *b = NULL; block *leftblock = deque->leftblock; block *rightblock = deque->rightblock; Py_ssize_t leftindex = deque->leftindex; Py_ssize_t rightindex = deque->rightindex; Py_ssize_t len=Py_SIZE(deque), halflen=len>>1; - int rv = 0; + int rv = -1; if (len <= 1) return 0; @@ -476,10 +477,10 @@ deque->state++; while (n > 0) { if (leftindex == 0) { - block *b = newblock(len); if (b == NULL) { - rv = -1; - goto done; + b = newblock(len); + if (b == NULL) + goto done; } b->rightlink = leftblock; CHECK_END(leftblock->leftlink); @@ -487,6 +488,7 @@ leftblock = b; MARK_END(b->leftlink); leftindex = BLOCKLEN; + b = NULL; } assert(leftindex > 0); @@ -511,7 +513,7 @@ if (rightindex == -1) { block *prevblock = rightblock->leftlink; assert(leftblock != rightblock); - freeblock(rightblock); + b = rightblock; CHECK_NOT_END(prevblock); MARK_END(prevblock->rightlink); rightblock = prevblock; @@ -520,10 +522,10 @@ } while (n < 0) { if (rightindex == BLOCKLEN - 1) { - block *b = newblock(len); if (b == NULL) { - rv = -1; - goto done; + b = newblock(len); + if (b == NULL) + goto done; } b->leftlink = rightblock; CHECK_END(rightblock->rightlink); @@ -531,6 +533,7 @@ rightblock = b; MARK_END(b->rightlink); rightindex = -1; + b = NULL; } assert (rightindex < BLOCKLEN - 1); @@ -555,14 +558,17 @@ if (leftindex == BLOCKLEN) { block *nextblock = leftblock->rightlink; assert(leftblock != rightblock); - freeblock(leftblock); + b = leftblock; CHECK_NOT_END(nextblock); MARK_END(nextblock->leftlink); leftblock = nextblock; leftindex = 0; } } + rv = 0; done: + if (b != NULL) + freeblock(b); deque->leftblock = leftblock; deque->rightblock = rightblock; deque->leftindex = leftindex; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 14 02:04:14 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 14 Jul 2013 02:04:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Use_a_do-while_loop_in_the?= =?utf-8?q?_inner_loop_for_rotate_=28m_is_always_greater_than?= Message-ID: <3bt7QQ0vM8z7LmB@mail.python.org> http://hg.python.org/cpython/rev/f04ce860b6f8 changeset: 84619:f04ce860b6f8 user: Raymond Hettinger date: Sat Jul 13 17:03:58 2013 -0700 summary: Use a do-while loop in the inner loop for rotate (m is always greater than zero). files: Modules/_collectionsmodule.c | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -506,13 +506,15 @@ rightindex -= m; leftindex -= m; n -= m; - while (m--) + do { *(dest--) = *(src--); + } while (--m); } if (rightindex == -1) { block *prevblock = rightblock->leftlink; assert(leftblock != rightblock); + assert(b == NULL); b = rightblock; CHECK_NOT_END(prevblock); MARK_END(prevblock->rightlink); @@ -551,13 +553,15 @@ leftindex += m; rightindex += m; n += m; - while (m--) + do { *(dest++) = *(src++); + } while (--m); } if (leftindex == BLOCKLEN) { block *nextblock = leftblock->rightlink; assert(leftblock != rightblock); + assert(b == NULL); b = leftblock; CHECK_NOT_END(nextblock); MARK_END(nextblock->leftlink); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 14 03:57:47 2013 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 14 Jul 2013 03:57:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Remove_spurious_backticks=2E?= Message-ID: <3bt9xR617mz7Lnn@mail.python.org> http://hg.python.org/peps/rev/b8e681254677 changeset: 4993:b8e681254677 user: Guido van Rossum date: Sat Jul 13 18:57:50 2013 -0700 summary: Remove spurious backticks. files: pep-0448.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0448.txt b/pep-0448.txt --- a/pep-0448.txt +++ b/pep-0448.txt @@ -150,8 +150,8 @@ If they are removed completely, a function call will look like this:: function( - argument or keyword_argument or `*`args or **kwargs, - argument or keyword_argument or `*`args or **kwargs, + argument or keyword_argument or *args or **kwargs, + argument or keyword_argument or *args or **kwargs, ... ) -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 14 04:27:12 2013 From: python-checkins at python.org (ned.deily) Date: Sun, 14 Jul 2013 04:27:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Closes_Issue_=2318442=3A_?= =?utf-8?q?fix_typo_=28noticed_by_F=C3=A9vry_Thibault=29=2E?= Message-ID: <3btBbN3Kklz7Llp@mail.python.org> http://hg.python.org/devguide/rev/291c17c3d83f changeset: 625:291c17c3d83f user: Ned Deily date: Sat Jul 13 19:26:50 2013 -0700 summary: Closes Issue #18442: fix typo (noticed by F?vry Thibault). files: developers.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/developers.rst b/developers.rst --- a/developers.rst +++ b/developers.rst @@ -24,7 +24,7 @@ Permissions History ------------------- -- Ethan Furman was given prush privileges on May 11 2013 by BAC, for PEP 435 +- Ethan Furman was given push 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 -- Repository URL: http://hg.python.org/devguide From solipsis at pitrou.net Sun Jul 14 05:50:21 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 14 Jul 2013 05:50:21 +0200 Subject: [Python-checkins] Daily reference leaks (f04ce860b6f8): sum=0 Message-ID: results for f04ce860b6f8 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogzjykOr', '-x'] From python-checkins at python.org Sun Jul 14 07:30:49 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 14 Jul 2013 07:30:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Tweak_the_deque_struct_by_?= =?utf-8?q?moving_the_least_used_fields_=28maxlen_and_weakref=29_to?= Message-ID: <3btGgF0KKSz7Lpf@mail.python.org> http://hg.python.org/cpython/rev/c952f3d122ae changeset: 84620:c952f3d122ae user: Raymond Hettinger date: Sat Jul 13 22:30:25 2013 -0700 summary: Tweak the deque struct by moving the least used fields (maxlen and weakref) to the end. files: Modules/_collectionsmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -119,8 +119,8 @@ block *rightblock; Py_ssize_t leftindex; /* in range(BLOCKLEN) */ Py_ssize_t rightindex; /* in range(BLOCKLEN) */ + long state; /* incremented whenever the indices move */ Py_ssize_t maxlen; - long state; /* incremented whenever the indices move */ PyObject *weakreflist; /* List of weak references */ } dequeobject; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 14 07:49:26 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 14 Jul 2013 07:49:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDMy?= =?utf-8?q?=3A__Fix_unintended_API_change_in_the_sched_module?= Message-ID: <3btH4k1tVcz7Lmh@mail.python.org> http://hg.python.org/cpython/rev/359002d4370d changeset: 84621:359002d4370d branch: 3.3 parent: 84615:bc3a34e47923 user: Raymond Hettinger date: Sat Jul 13 22:42:09 2013 -0700 summary: Issue #18432: Fix unintended API change in the sched module files: Lib/sched.py | 2 +- Lib/test/test_sched.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/sched.py b/Lib/sched.py --- a/Lib/sched.py +++ b/Lib/sched.py @@ -165,4 +165,4 @@ # the actual order they would be retrieved. with self._lock: events = self._queue[:] - return map(heapq.heappop, [events]*len(events)) + return list(map(heapq.heappop, [events]*len(events))) diff --git a/Lib/test/test_sched.py b/Lib/test/test_sched.py --- a/Lib/test/test_sched.py +++ b/Lib/test/test_sched.py @@ -172,7 +172,7 @@ e3 = scheduler.enterabs(now + 0.03, 1, fun) # queue property is supposed to return an order list of # upcoming events - self.assertEqual(list(scheduler.queue), [e1, e2, e3, e4, e5]) + self.assertEqual(scheduler.queue, [e1, e2, e3, e4, e5]) def test_args_kwargs(self): flag = [] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,9 @@ - Issue #18431: The new email header parser now decodes RFC2047 encoded words in structured headers. +- Issue #18432: The sched module's queue method was incorrectly returning + an iterator instead of a list. + - Issue #18044: The new email header parser was mis-parsing encoded words where an encoded character immediately followed the '?' that follows the CTE character, resulting in a decoding failure. They are now decoded correctly. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 14 07:49:27 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 14 Jul 2013 07:49:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3btH4l3tGbz7Lmh@mail.python.org> http://hg.python.org/cpython/rev/21b0257ed2a6 changeset: 84622:21b0257ed2a6 parent: 84620:c952f3d122ae parent: 84621:359002d4370d user: Raymond Hettinger date: Sat Jul 13 22:48:49 2013 -0700 summary: merge files: Lib/sched.py | 2 +- Lib/test/test_sched.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/sched.py b/Lib/sched.py --- a/Lib/sched.py +++ b/Lib/sched.py @@ -164,4 +164,4 @@ # the actual order they would be retrieved. with self._lock: events = self._queue[:] - return map(heapq.heappop, [events]*len(events)) + return list(map(heapq.heappop, [events]*len(events))) diff --git a/Lib/test/test_sched.py b/Lib/test/test_sched.py --- a/Lib/test/test_sched.py +++ b/Lib/test/test_sched.py @@ -172,7 +172,7 @@ e3 = scheduler.enterabs(now + 0.03, 1, fun) # queue property is supposed to return an order list of # upcoming events - self.assertEqual(list(scheduler.queue), [e1, e2, e3, e4, e5]) + self.assertEqual(scheduler.queue, [e1, e2, e3, e4, e5]) def test_args_kwargs(self): flag = [] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -157,6 +157,9 @@ - Issue #18431: The new email header parser now decodes RFC2047 encoded words in structured headers. +- Issue #18432: The sched module's queue method was incorrectly returning + an iterator instead of a list. + - Issue #18044: The new email header parser was mis-parsing encoded words where an encoded character immediately followed the '?' that follows the CTE character, resulting in a decoding failure. They are now decoded correctly. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 14 09:12:11 2013 From: python-checkins at python.org (ezio.melotti) Date: Sun, 14 Jul 2013 09:12:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_=2318021=3A_remove_broken?= =?utf-8?q?_link_to_the_Apple_Style_Guide=2E__Patch_by_Madison_May=2E?= Message-ID: <3btJwC3z70z7Lq2@mail.python.org> http://hg.python.org/devguide/rev/dcb9ec098781 changeset: 626:dcb9ec098781 user: Ezio Melotti date: Sun Jul 14 09:11:57 2013 +0200 summary: #18021: remove broken link to the Apple Style Guide. Patch by Madison May. files: docquality.rst | 5 ----- documenting.rst | 11 ----------- 2 files changed, 0 insertions(+), 16 deletions(-) diff --git a/docquality.rst b/docquality.rst --- a/docquality.rst +++ b/docquality.rst @@ -19,11 +19,6 @@ http://docs.python.org/dev/. The in-development and most recent 2.x and 3.x maintenance :ref:`branches ` are rebuilt once per day. -If you would like a technical documentation style guide, the `Apple -Publications Style Guide -`_ -is recommended. - If you care to get more involved with documentation, you may also consider subscribing to the `docs at python.org mailing list `_. diff --git a/documenting.rst b/documenting.rst --- a/documenting.rst +++ b/documenting.rst @@ -61,14 +61,6 @@ Style guide =========== -The Python documentation should follow the `Apple Publications Style Guide`_ -wherever possible. This particular style guide was selected mostly because it -seems reasonable and is easy to get online. - -Topics which are either not covered in Apple's style guide or treated -differently in Python documentation will be discussed in this -document. - Use of whitespace ----------------- @@ -266,9 +258,6 @@ making false assumptions about the language ("I was surprised by ..."). -.. _Apple Publications Style Guide: http://developer.apple.com/mac/library/documentation/UserExperience/Conceptual/APStyleGuide/APSG_2009.pdf - - reStructuredText Primer ======================= -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Jul 14 15:28:32 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 14 Jul 2013 15:28:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Assorted_PEP_426_updates?= Message-ID: <3btTGS3rkXz7LkQ@mail.python.org> http://hg.python.org/peps/rev/067d3c3c1351 changeset: 4994:067d3c3c1351 user: Nick Coghlan date: Sun Jul 14 23:27:22 2013 +1000 summary: Assorted PEP 426 updates * Merge conditional and unconditional deps * Don't trust public index server "Provides" metadata * Rename pymeta to pydist (schema file name change postponed for better diff) * Bring schema file up to date (I think - could use an audit) files: pep-0426.txt | 430 +++++++++-------------- pep-0426/pymeta-schema.json | 107 ++--- 2 files changed, 229 insertions(+), 308 deletions(-) diff --git a/pep-0426.txt b/pep-0426.txt --- a/pep-0426.txt +++ b/pep-0426.txt @@ -13,7 +13,7 @@ Requires: 440 Created: 30 Aug 2012 Post-History: 14 Nov 2012, 5 Feb 2013, 7 Feb 2013, 9 Feb 2013, - 27 May 2013, 20 Jun 2013, 23 Jun 2013 + 27 May 2013, 20 Jun 2013, 23 Jun 2013, 14 Jul 2013 Replaces: 345 @@ -63,13 +63,15 @@ * 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 + * an updated wheel PEP (v1.1) to add pydist.json (and possibly convert + the wheel metadata file from Key:Value to JSON) + * an updated installation database PEP both for pydist.json (and possibly convert + the wheel metadata file from Key:Value to JSON) + * an alternative to *.pth files that avoids system global side effects + and better supports runtime selection of dependencies * 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. + * a PEP to cover bundling ``pip`` with the CPython installers 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 @@ -361,7 +363,7 @@ Metadata files -------------- -The information defined in this PEP is serialised to ``pymeta.json`` +The information defined in this PEP is serialised to ``pydist.json`` files for some use cases. These are files containing UTF-8 encoded JSON metadata. @@ -370,11 +372,11 @@ There are three standard locations for these metadata files: -* as a ``{distribution}-{version}.dist-info/pymeta.json`` file in an +* as a ``{distribution}-{version}.dist-info/pydist.json`` file in an ``sdist`` source distribution archive -* as a ``{distribution}-{version}.dist-info/pymeta.json`` file in a ``wheel`` +* as a ``{distribution}-{version}.dist-info/pydist.json`` file in a ``wheel`` binary distribution archive -* as a ``{distribution}-{version}.dist-info/pymeta.json`` file in a local +* as a ``{distribution}-{version}.dist-info/pydist.json`` file in a local Python installation database .. note:: @@ -422,21 +424,16 @@ * ``source_url`` * ``extras`` * ``meta_requires`` -* ``meta_may_require`` * ``run_requires`` -* ``run_may_require`` * ``test_requires`` -* ``test_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-dependencies.json``. +be ``pydist-dependencies.json``. Included documents @@ -457,7 +454,7 @@ A `jsonschema `__ description of the distribution metadata is `available -`__. +`__. This schema does NOT currently handle validation of some of the more complex string fields (instead treating them as opaque strings). @@ -924,6 +921,10 @@ working on this distribution (but do not fit into one of the other dependency categories). +Within each of these categories, distributions may also declare "Extras". +Extras are dependencies that may be needed for some optional functionality, +or which are otherwise complementary to the distribution. + Dependency management is heavily dependent on the version identification and specification scheme defined in PEP 440. @@ -932,15 +933,58 @@ 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 +Dependency specifiers +--------------------- + +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 handle this, dependency +specifiers are mappings with the following subfields: + +* ``requires``: a list of `requirement specifiers + `__ needed to satisfy the dependency +* ``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. + +``requires`` is the only required subfield. When it is the only subfield, the +dependencies are said to be *unconditional*. If ``extra`` or ``environment`` +is specified, then the dependencies are *conditional*. + +All three fields may be supplied, indicating that the dependencies are +needed only when the named extra is requested in a particular environment. + +Automated tools MUST combine related dependency specifiers (those with +common values for ``extra`` and ``environment``) into a single specifier +listing multiple requirements when serialising metadata or +passing it to an install hook. + +Despite this required normalisation, the same extra name or environment +marker MAY appear in multiple conditional dependencies. This may happen, +for example, if an extra itself only needs some of its dependencies in +specific environments. It is only the combination of extras and environment +markers that is required to be unique in a list of dependency specifiers. + +Any extras referenced from a dependency specifier MUST be named in the +`Extras`_ field for this distribution. This helps avoid typographical +errors and also makes it straightforward to identify the available extras +without scanning the full set of dependencies. + + +Requirement specifiers +---------------------- + +Individual requirements are defined as strings containing a distribution +name (as found in the ``name`` field). The distribution name may be followed by an extras specifier (enclosed in square brackets) and by a version specifier or direct reference (within parentheses). +Whitespace is permitted between the distribution name and an opening +square bracket or parenthesis. Whitespace is also permitted between a +closing square bracket and an opening parenthesis. + See `Extras (optional dependencies)`_ for details on extras and PEP 440 for details on version specifiers and direct references. @@ -949,7 +993,7 @@ 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:: +Example requirement specifiers:: "Flask" "Django" @@ -959,36 +1003,6 @@ "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. - - Mapping dependencies to development and distribution activities --------------------------------------------------------------- @@ -999,44 +1013,33 @@ * Implied runtime dependencies: * ``meta_requires`` - * ``meta_may_require`` * ``run_requires`` - * ``run_may_require`` * Implied build dependencies: * ``build_requires`` - * ``build_may_require`` * If running the distribution's test suite as part of the build process, request the ``:meta:``, ``:run:`` and ``:test:`` extras to also install: * ``meta_requires`` - * ``meta_may_require`` * ``run_requires`` - * ``run_may_require`` * ``test_requires`` - * ``test_may_require`` * Implied development and publication dependencies: * ``meta_requires`` - * ``meta_may_require`` * ``run_requires`` - * ``run_may_require`` * ``build_requires`` - * ``build_may_require`` * ``test_requires`` - * ``test_may_require`` * ``dev_requires`` - * ``dev_may_require`` The notation described in `Extras (optional dependencies)`_ SHOULD be used to determine exactly what gets installed for various operations. -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. +Installation tools SHOULD report an error if dependencies cannot be +satisfied, MUST at least emit a warning, and MAY allow the user to force +the installation to proceed regardless. See Appendix B for an overview of mapping these dependencies to an RPM spec file. @@ -1046,8 +1049,8 @@ ------ A list of optional sets of dependencies that may be used to define -conditional dependencies in ``"may_distribute"``, ``"run_may_require"`` and -similar fields. See `Extras (optional dependencies)`_ for details. +conditional dependencies in dependency fields. See +`Extras (optional dependencies)`_ for details. The names of extras MUST abide by the same restrictions as those for distribution names. @@ -1080,39 +1083,13 @@ Example:: - "meta_requires": ["ComfyUpholstery (== 1.0a2)", - "ComfySeatCushion (== 1.0a2)"] - - -Meta may require ----------------- - -An abbreviation of "metadistribution may require". This is a list of -subdistributions that can easily be installed and used together by -depending on this metadistribution, but are not required in all -circumstances. - -Any extras referenced from this field MUST be named in the `Extras`_ field. - -In this field, automated tools: - -* MUST allow strict version matching -* MUST NOT allow more permissive version specifiers. -* MAY allow direct references - -Public index servers SHOULD NOT allow the use of direct references in -uploaded distributions. Direct references are intended primarily as a -tool for software integrators rather than publishers. - -Distributions that rely on direct references to platform specific binary -archives SHOULD defined appropriate constraints in their -``supports_environments`` field. - -Example:: - - "meta_may_require": [ + "meta_requires": { - "dependencies": ["CupOfTeaAtEleven (== 1.0a2)"], + "requires": ["ComfyUpholstery (== 1.0a2)", + "ComfySeatCushion (== 1.0a2)"] + }, + { + "requires": ["CupOfTeaAtEleven (== 1.0a2)"], "environment": "'linux' in sys.platform" } ] @@ -1129,31 +1106,16 @@ Example:: - "run_requires": ["SciPy", "PasteDeploy", "zope.interface (>3.5.0)"] - - -Run may require ---------------- - -A list of other distributions that may be needed to actually run this -distribution, based on the extras requested and the target deployment -environment. - -Any extras referenced from this field MUST be named in the `Extras`_ field. - -Automated tools MUST NOT allow strict version matching clauses or direct -references in this field - if permitted at all, such clauses should appear -in ``meta_may_require`` instead. - -Example:: - - "run_may_require": [ + "run_requires": { - "dependencies": ["pywin32 (>1.0)"], + "requires": ["SciPy", "PasteDeploy", "zope.interface (>3.5.0)"] + }, + { + "requires": ["pywin32 (>1.0)"], "environment": "sys.platform == 'win32'" }, { - "dependencies": ["SoftCushions"], + "requires": ["SoftCushions"], "extra": "warmup" } ] @@ -1173,32 +1135,16 @@ 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. - -Any extras referenced from this field MUST be named in the `Extras`_ field. - -Automated tools MAY disallow strict version matching clauses and direct -references in this field and SHOULD at least emit a warning for such clauses. - -Public index servers SHOULD NOT allow strict version matching clauses or -direct references in this field. - -Example:: - - "test_may_require": [ + "test_requires": { - "dependencies": ["pywin32 (>1.0)"], + "requires": ["unittest2"] + }, + { + "requires": ["pywin32 (>1.0)"], "environment": "sys.platform == 'win32'" }, { - "dependencies": ["CompressPadding"], + "requires": ["CompressPadding"], "extra": "warmup" } ] @@ -1221,39 +1167,16 @@ 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 an sdist, source archive or -VCS checkout), 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. - -Automated tools MAY disallow strict version matching clauses and direct -references in this field and SHOULD at least emit a warning for such clauses. - -Public index servers SHOULD NOT allow strict version matching clauses or -direct references in this field. - -Example:: - - "build_may_require": [ + "build_requires": { - "dependencies": ["pywin32 (>1.0)"], + "requires": ["setuptools (>= 0.7)"] + }, + { + "requires": ["pywin32 (>1.0)"], "environment": "sys.platform == 'win32'" }, { - "dependencies": ["cython"], + "requires": ["cython"], "extra": "c-accelerators" } ] @@ -1280,35 +1203,12 @@ 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. - -Automated tools MAY disallow strict version matching clauses and direct -references in this field and SHOULD at least emit a warning for such clauses. - -Public index servers SHOULD NOT allow strict version matching clauses or -direct references in this field. - -Example:: - - "dev_may_require": [ + "dev_requires": { - "dependencies": ["pywin32 (>1.0)"], + "requires": ["hgtools", "sphinx (>= 1.0)"] + }, + { + "requires": ["pywin32 (>1.0)"], "environment": "sys.platform == 'win32'" } ] @@ -1334,11 +1234,8 @@ satisfy any projects that require the now obsolete distribution's name. To avoid malicious hijacking of names, when interpreting metadata retrieved -from a public index server, automated tools MUST prefer the distribution -named in a version specifier over other distributions using that -distribution's name in a ``"provides"`` entry. Index servers MAY drop such -entries from the metadata they republish, but SHOULD NOT refuse to publish -such distributions. +from a public index server, automated tools MUST NOT pay any attention to +``"provides"`` entries that do not correspond to a published distribution. However, to appropriately handle project forks and mergers, automated tools MUST accept ``"provides"`` entries that name other distributions when the @@ -1346,7 +1243,7 @@ corresponding ``"obsoleted_by"`` entry in the metadata for the named distribution. -A distribution may also provide a "virtual" project name, which does +A distribution may wish to depend on 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 @@ -1354,13 +1251,20 @@ 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. +To handle this case in a way that doesn't allow for name hijacking, the +authors of the distribution that first defines the virtual dependency should +create a project on the public index server with the corresponding name, and +depend on the specific distribution that should be used if no other provider +is already installed. This also has the benefit of publishing the default +provider in a way that automated tools will understand. + +A version declaration may be supplied as part of an entry in the provides +field 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"] + "provides": ["AnotherProject (3.4)", "virtual-package"] Obsoleted by @@ -1596,15 +1500,15 @@ "name": "ComfyChair", "extras": ["warmup", "c-accelerators"] - "run_may_require": [ + "run_requires": [ { - "dependencies": ["SoftCushions"], + "requires": ["SoftCushions"], "extra": "warmup" } ] - "build_may_require": [ + "build_requires": [ { - "dependencies": ["cython"], + "requires": ["cython"], "extra": "c-accelerators" } ] @@ -1617,18 +1521,20 @@ * Multiple extras can be requested by separating them with a comma within the brackets. + * The following special extras request processing of the corresponding lists of dependencies: - * ``:meta:``: ``meta_requires`` and ``meta_may_require`` - * ``:run:``: ``run_requires`` and ``run_may_require`` - * ``:test:``: ``test_requires`` and ``test_may_require`` - * ``:build:``: ``build_requires`` and ``build_may_require`` - * ``:dev:``: ``dev_requires`` and ``dev_may_require`` + * ``:meta:``: ``meta_requires`` + * ``:run:``: ``run_requires`` + * ``:test:``: ``test_requires`` + * ``:build:``: ``build_requires`` + * ``:dev:``: ``dev_requires`` * ``:*:``: process *all* dependency lists * The ``*`` character as an extra is a wild card that enables all of the entries defined in the distribution's ``extras`` field. + * Extras may be explicitly excluded by prefixing their name with a ``-`` character (this is useful in conjunction with ``*`` to exclude only particular extras that are definitely not wanted, while enabling all @@ -1646,14 +1552,14 @@ The full set of dependency requirements is then based on the top level dependencies, along with those of any requested extras. -Dependency examples:: - - "run_requires": ["ComfyChair[warmup]"] - -> requires ``ComfyChair`` and ``SoftCushions`` at run time - - "run_requires": ["ComfyChair[*]"] - -> requires ``ComfyChair`` and ``SoftCushions`` at run time, but - will also pick up any new extras defined in later versions +Dependency examples (showing just the ``requires`` subfield):: + + "requires": ["ComfyChair[warmup]"] + -> requires ``ComfyChair`` and ``SoftCushions`` + + "requires": ["ComfyChair[*]"] + -> requires ``ComfyChair`` and ``SoftCushions``, but will also + pick up any new extras defined in later versions Command line examples:: @@ -1670,7 +1576,8 @@ -> as above, but also installs dependencies needed to run the tests pip install ComfyChair[-,:*:,*] - -> installs the full set of development dependencies + -> installs the full set of development dependencies, but avoids + installing ComfyChair itself Environment markers @@ -1693,15 +1600,15 @@ requires PyWin32 both at runtime and buildtime when using Windows:: "name": "ComfyChair", - "run_may_require": [ + "run_requires": [ { - "dependencies": ["pywin32 (>1.0)"], + "requires": ["pywin32 (>1.0)"], "environment": "sys.platform == 'win32'" } ] - "build_may_require": [ + "build_requires": [ { - "dependencies": ["pywin32 (>1.0)"], + "requires": ["pywin32 (>1.0)"], "environment": "sys.platform == 'win32'" } ] @@ -1767,9 +1674,9 @@ The metadata specification may be updated with clarifications without requiring a new PEP or a change to the metadata version. -Adding new features (other than through the extension mechanism), or -changing the meaning of existing fields, requires a new metadata version -defined in a new PEP. +Changing the meaning of existing fields or adding new features (other than +through the extension mechanism) requires a new metadata version defined in +a new PEP. Appendix A: Conversion notes for legacy metadata @@ -1801,28 +1708,21 @@ Appendix B: Mapping dependency declarations to an RPM SPEC file =============================================================== - As an example of mapping this PEP 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 ``meta_requires``, ``run_requires`` and applicable -``meta_may_require`` ``run_may_require`` dependencies would be mapped +The ``meta_requires`` and ``run_requires`` dependencies would be mapped to the Requires dependencies for the "example" RPM (a mapping from environment markers relevant to Linux 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. +The ``build_requires`` dependencies would be mapped to the BuildRequires +dependencies for the "example" RPM. All defined dependencies relevant to Linux, including those in -``dev_requires``, ``test_requires``, ``dev_may_require``, and -``test_may_require`` would become Requires dependencies for the -"example-devel" RPM. - -If the project did define any extras, those would likely be mapped to -additional virtual RPMs with appropriate BuildRequires and Requires -entries based on the details of the dependency specifications. +``dev_requires`` and ``test_requires`` would become Requires dependencies +for the "example-devel" RPM. A documentation toolchain dependency like Sphinx would either go in ``build_requires`` (for example, if man pages were included in the @@ -1831,6 +1731,20 @@ project website). This would be enough to allow an automated converter to map it to an appropriate dependency in the spec file. +If the project did define any extras, those could be mapped to additional +virtual RPMs with appropriate BuildRequires and Requires entries based on +the details of the dependency specifications. Alternatively, they could +be mapped to other system package manager features (such as package lists +in ``yum``). + +Other system package managers may have other options for dealing with +extras (Debian packagers, for example, would have the option to map them +to "Recommended" or "Suggested" package entries). + +The metadata extension format should also allow distribution specific hints +to be included in the upstream project metadata without needing to manually +duplicate any of the upstream metadata in a distribution specific format. + Appendix C: Summary of differences from \PEP 345 ================================================= @@ -1986,7 +1900,7 @@ --------------------------------------------------- The new extras system allows distributions to declare optional -behaviour, and to use the ``*may_require`` fields to indicate when +behaviour, and to use the dependency fields to indicate when particular dependencies are needed only to support that behaviour. 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`` @@ -2011,6 +1925,10 @@ the chosen extension, and the new extras mechanism, allowing support for particular extensions to be provided as optional features. +Possible future uses for extensions include declaration of plugins for +other distributions, hints for automatic conversion to Linux system +packages, and inclusion of CVE references to mark security releases. + Support for install hooks --------------------------- @@ -2189,10 +2107,9 @@ At some point after acceptance of the PEP, I will likely submit the following MIME type registration requests to IANA: -* Full metadata: ``application/vnd.python.pymeta+json`` -* Abbreviated metadata: ``application/vnd.python.pymeta-short+json`` +* Full metadata: ``application/vnd.python.pydist+json`` * Essential dependency resolution metadata: - ``application/vnd.python.pymeta-dependencies+json`` + ``application/vnd.python.pydist-dependencies+json`` It's even possible we may be able to just register the ``vnd.python`` namespace under the banner of the PSF rather than having to register @@ -2365,6 +2282,15 @@ expressiveness. +Separate lists for conditional and unconditional dependencies +------------------------------------------------------------- + +Earlier versions of this PEP used separate lists for conditional and +unconditional dependencies. This turned out to be annoying to handle in +automated tools and removing it also made the PEP and metadata schema +substantially shorter, suggesting it was actually harder to explain as well. + + Disallowing underscores in distribution names --------------------------------------------- diff --git a/pep-0426/pymeta-schema.json b/pep-0426/pymeta-schema.json --- a/pep-0426/pymeta-schema.json +++ b/pep-0426/pymeta-schema.json @@ -17,7 +17,7 @@ "name": { "description": "The name of the distribution.", "type": "string", - "pattern": "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])?$" + "$ref": "#/definitions/valid_name" }, "version": { "description": "The distribution's public version identifier", @@ -103,65 +103,43 @@ "$ref": "#/definitions/extra_name" } }, - "distributes": { + "meta_requires": { "description": "A list of subdistributions made available through this metadistribution.", "type": "array", "$ref": "#/definitions/dependencies" }, - "may_distribute": { - "description": "A list of subdistributions that may be made available through this metadistribution, based on the extras requested and the target deployment environment.", - "$ref": "#/definitions/conditional_dependencies" - }, "run_requires": { - "description": "A list of other distributions needed when to run this distribution.", + "description": "A list of other distributions needed to run this distribution.", "type": "array", "$ref": "#/definitions/dependencies" }, - "run_may_require": { - "description": "A list of other distributions that may be needed when this distribution is deployed, based on the extras requested and the target deployment environment.", - "$ref": "#/definitions/conditional_dependencies" - }, "test_requires": { "description": "A list of other distributions needed when this distribution is tested.", "type": "array", "$ref": "#/definitions/dependencies" }, - "test_may_require": { - "description": "A list of other distributions that may be needed when this distribution is tested, based on the extras requested and the target deployment environment.", - "type": "array", - "$ref": "#/definitions/conditional_dependencies" - }, "build_requires": { "description": "A list of other distributions needed when this distribution is built.", "type": "array", "$ref": "#/definitions/dependencies" }, - "build_may_require": { - "description": "A list of other distributions that may be needed when this distribution is built, based on the extras requested and the target deployment environment.", - "type": "array", - "$ref": "#/definitions/conditional_dependencies" - }, "dev_requires": { "description": "A list of other distributions needed when this distribution is developed.", "type": "array", "$ref": "#/definitions/dependencies" }, - "dev_may_require": { - "description": "A list of other distributions that may be needed when this distribution is developed, based on the extras requested and the target deployment environment.", - "type": "array", - "$ref": "#/definitions/conditional_dependencies" - }, "provides": { - "description": "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.", + "description": "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)", "type": "array", "items": { - "type": "string" + "type": "string", + "$ref": "#/definitions/provides_declaration" } }, "obsoleted_by": { "description": "A string that indicates that this project is no longer being developed. The named project provides a substitute or replacement.", "type": "string", - "$ref": "#/definitions/version_specifier" + "$ref": "#/definitions/requirement" }, "supports_environments": { "description": "A list of strings specifying the environments that the distribution explicitly supports.", @@ -171,9 +149,19 @@ "$ref": "#/definitions/environment_marker" } }, - "metabuild_hooks": { - "description": "The metabuild_hooks field is used to define various operations that may be invoked on a distribution in a platform independent manner.", - "type": "object" + "install_hooks": { + "description": "The install_hooks field is used to define various operations that may be invoked on a distribution in a platform independent manner.", + "type": "object", + "properties": { + "postinstall": { + "type": "string", + "$ref": "#/definitions/entry_point" + }, + "preuninstall": { + "type": "string", + "$ref": "#/definitions/entry_point" + } + } }, "extensions": { "description": "Extensions to the metadata may be present in a mapping under the 'extensions' key.", @@ -181,7 +169,7 @@ } }, - "required": ["metadata_version", "name", "version"], + "required": ["metadata_version", "name", "version", "summary"], "additionalProperties": false, "definitions": { @@ -207,41 +195,48 @@ "dependencies": { "type": "array", "items": { - "type": "string", - "$ref": "#/definitions/version_specifier" + "type": "object", + "$ref": "#/definitions/dependency" } }, - "conditional_dependencies": { - "type": "array", - "items": { - "type": "object", - "properties": { - "extra": { + "dependency": { + "type": "object", + "properties": { + "extra": { + "type": "string", + "$ref": "#/definitions/valid_name" + }, + "environment": { + "type": "string", + "$ref": "#/definitions/environment_marker" + }, + "requires": { + "type": "array", + "items": { "type": "string", - "$ref": "#/definitions/extra_name" - }, - "environment": { - "type": "string", - "$ref": "#/definitions/environment_marker" - }, - "dependencies": { - "type": "array", - "$ref": "#/definitions/dependencies" + "$ref": "#/definitions/requirement" } - }, - "required": ["dependencies"], - "additionalProperties": false - } + } + }, + "required": ["requires"], + "additionalProperties": false }, - "version_specifier": { + "valid_name": { + "type": "string", + "pattern": "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])?$" + }, + "requirement": { "type": "string" }, - "extra_name": { + "provides_declaration": { "type": "string" }, "environment_marker": { "type": "string" }, + "entry_point": { + "type": "string" + }, "document_name": { "type": "string" } -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 14 15:28:33 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 14 Jul 2013 15:28:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Rename_PEP_426_schema_file?= Message-ID: <3btTGT5WLKz7Lmy@mail.python.org> http://hg.python.org/peps/rev/dbad85dcf766 changeset: 4995:dbad85dcf766 user: Nick Coghlan date: Sun Jul 14 23:28:14 2013 +1000 summary: Rename PEP 426 schema file files: pep-0426/pymeta-schema.json | 0 1 files changed, 0 insertions(+), 0 deletions(-) diff --git a/pep-0426/pymeta-schema.json b/pep-0426/pydist-schema.json rename from pep-0426/pymeta-schema.json rename to pep-0426/pydist-schema.json -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 14 15:29:47 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 14 Jul 2013 15:29:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Markup_fix?= Message-ID: <3btTHv5C4wz7LnQ@mail.python.org> http://hg.python.org/peps/rev/62f9d56b645a changeset: 4996:62f9d56b645a user: Nick Coghlan date: Sun Jul 14 23:29:39 2013 +1000 summary: Markup fix files: pep-0426.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0426.txt b/pep-0426.txt --- a/pep-0426.txt +++ b/pep-0426.txt @@ -67,7 +67,7 @@ the wheel metadata file from Key:Value to JSON) * an updated installation database PEP both for pydist.json (and possibly convert the wheel metadata file from Key:Value to JSON) - * an alternative to *.pth files that avoids system global side effects + * an alternative to \*.pth files that avoids system global side effects and better supports runtime selection of dependencies * a new static config PEP to standardise metadata generation and creation of sdists -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 14 15:50:59 2013 From: python-checkins at python.org (brett.cannon) Date: Sun, 14 Jul 2013 15:50:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=239893=3A_remove_an?= =?utf-8?q?_outdated_mention_of_the_Vim-related_files=2E?= Message-ID: <3btTmM0Y5dz7LnQ@mail.python.org> http://hg.python.org/cpython/rev/afd17a514117 changeset: 84623:afd17a514117 user: Brett Cannon date: Sun Jul 14 09:50:50 2013 -0400 summary: Issue #9893: remove an outdated mention of the Vim-related files. files: Misc/README | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Misc/README b/Misc/README --- a/Misc/README +++ b/Misc/README @@ -27,4 +27,3 @@ TextMate A TextMate bundle for Python development valgrind-python.supp Valgrind suppression file, see README.valgrind vgrindefs Python configuration for vgrind (a generic pretty printer) -Vim Python development utilities for the Vim editor -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 14 21:25:30 2013 From: python-checkins at python.org (ned.deily) Date: Sun, 14 Jul 2013 21:25:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Closes_=2318450=3A_fix_mo?= =?utf-8?q?re_typos_=28noticed_by_F=C3=A9vry_Thibault=29=2E?= Message-ID: <3btdBL29Dcz7LkF@mail.python.org> http://hg.python.org/devguide/rev/26a3ff53a7da changeset: 627:26a3ff53a7da user: Ned Deily date: Sun Jul 14 12:25:14 2013 -0700 summary: Closes #18450: fix more typos (noticed by F?vry Thibault). files: developers.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/developers.rst b/developers.rst --- a/developers.rst +++ b/developers.rst @@ -67,7 +67,7 @@ Melotti, R. David Murray and others. - Charles-Fran?ois Natali was given push privileges on May 19 2011 by Antoine - Pitrou, for general contributions, on recommandation by Victor Stinner, + Pitrou, for general contributions, on recommendation by Victor Stinner, Brian Curtin and others. - Nadeem Vawda was given push privileges on Apr 10 2011 by GFB, for @@ -231,7 +231,7 @@ for general contributions to Python. - Mark Dickinson was given SVN access on 6 January 2008 by Facundo - Batista for his work on mathemathics and number related issues. + Batista for his work on mathematics and number related issues. - Amaury Forgeot d'Arc was given SVN access on 9 November 2007 by MvL, for general contributions to Python. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Jul 14 21:46:04 2013 From: python-checkins at python.org (ned.deily) Date: Sun, 14 Jul 2013 21:46:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDUy?= =?utf-8?q?=3A_fix_several_=22occurrence=22_typos_=28reported_by_F=C3=A9vr?= =?utf-8?q?y_Thibault=29=2E?= Message-ID: <3btdf43tFYz7LkN@mail.python.org> http://hg.python.org/cpython/rev/8c935717fc8e changeset: 84624:8c935717fc8e branch: 2.7 parent: 84617:ba4c826848d5 user: Ned Deily date: Sun Jul 14 12:42:27 2013 -0700 summary: Issue #18452: fix several "occurrence" typos (reported by F?vry Thibault). files: Doc/howto/argparse.rst | 2 +- Doc/library/stdtypes.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -468,7 +468,7 @@ print answer We have introduced another action, "count", -to count the number of occurences of a specific optional arguments: +to count the number of occurrences of a specific optional arguments: .. code-block:: sh diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -743,10 +743,10 @@ +------------------+--------------------------------+----------+ | ``max(s)`` | largest item of *s* | | +------------------+--------------------------------+----------+ -| ``s.index(i)`` | index of the first occurence | | +| ``s.index(i)`` | index of the first occurrence | | | | of *i* in *s* | | +------------------+--------------------------------+----------+ -| ``s.count(i)`` | total number of occurences of | | +| ``s.count(i)`` | total number of occurrences of | | | | *i* in *s* | | +------------------+--------------------------------+----------+ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 14 21:46:05 2013 From: python-checkins at python.org (ned.deily) Date: Sun, 14 Jul 2013 21:46:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDUy?= =?utf-8?q?=3A_fix_several_=22occurrence=22_typos_=28reported_by_F=C3=A9vr?= =?utf-8?q?y_Thibault=29=2E?= Message-ID: <3btdf55s5Gz7Lp1@mail.python.org> http://hg.python.org/cpython/rev/1a93c624551f changeset: 84625:1a93c624551f branch: 3.3 parent: 84621:359002d4370d user: Ned Deily date: Sun Jul 14 12:43:16 2013 -0700 summary: Issue #18452: fix several "occurrence" typos (reported by F?vry Thibault). files: Doc/howto/argparse.rst | 2 +- Doc/library/configparser.rst | 2 +- Doc/library/stdtypes.rst | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -468,7 +468,7 @@ print(answer) We have introduced another action, "count", -to count the number of occurences of a specific optional arguments: +to count the number of occurrences of a specific optional arguments: .. code-block:: sh diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -539,7 +539,7 @@ * *delimiters*, default value: ``('=', ':')`` Delimiters are substrings that delimit keys from values within a section. The - first occurence of a delimiting substring on a line is considered a delimiter. + first occurrence of a delimiting substring on a line is considered a delimiter. This means values (but not keys) can contain the delimiters. See also the *space_around_delimiters* argument to diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -871,11 +871,11 @@ +--------------------------+--------------------------------+----------+ | ``max(s)`` | largest item of *s* | | +--------------------------+--------------------------------+----------+ -| ``s.index(x[, i[, j]])`` | index of the first occurence | \(8) | +| ``s.index(x[, i[, j]])`` | index of the first occurrence | \(8) | | | of *x* in *s* (at or after | | | | index *i* and before index *j*)| | +--------------------------+--------------------------------+----------+ -| ``s.count(x)`` | total number of occurences of | | +| ``s.count(x)`` | total number of occurrences of | | | | *x* in *s* | | +--------------------------+--------------------------------+----------+ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 14 21:46:07 2013 From: python-checkins at python.org (ned.deily) Date: Sun, 14 Jul 2013 21:46:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2318452=3A_fix_several_=22occurrence=22_typos_?= =?utf-8?q?=28reported_by_F=C3=A9vry_Thibault=29=2E?= Message-ID: <3btdf70f2sz7Lp1@mail.python.org> http://hg.python.org/cpython/rev/db9fe49069ed changeset: 84626:db9fe49069ed parent: 84623:afd17a514117 parent: 84625:1a93c624551f user: Ned Deily date: Sun Jul 14 12:45:18 2013 -0700 summary: Closes #18452: fix several "occurrence" typos (reported by F?vry Thibault). files: Doc/howto/argparse.rst | 2 +- Doc/library/configparser.rst | 2 +- Doc/library/stdtypes.rst | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -468,7 +468,7 @@ print(answer) We have introduced another action, "count", -to count the number of occurences of a specific optional arguments: +to count the number of occurrences of a specific optional arguments: .. code-block:: sh diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -539,7 +539,7 @@ * *delimiters*, default value: ``('=', ':')`` Delimiters are substrings that delimit keys from values within a section. The - first occurence of a delimiting substring on a line is considered a delimiter. + first occurrence of a delimiting substring on a line is considered a delimiter. This means values (but not keys) can contain the delimiters. See also the *space_around_delimiters* argument to diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -871,11 +871,11 @@ +--------------------------+--------------------------------+----------+ | ``max(s)`` | largest item of *s* | | +--------------------------+--------------------------------+----------+ -| ``s.index(x[, i[, j]])`` | index of the first occurence | \(8) | +| ``s.index(x[, i[, j]])`` | index of the first occurrence | \(8) | | | of *x* in *s* (at or after | | | | index *i* and before index *j*)| | +--------------------------+--------------------------------+----------+ -| ``s.count(x)`` | total number of occurences of | | +| ``s.count(x)`` | total number of occurrences of | | | | *x* in *s* | | +--------------------------+--------------------------------+----------+ -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Jul 15 05:48:39 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 15 Jul 2013 05:48:39 +0200 Subject: [Python-checkins] Daily reference leaks (db9fe49069ed): sum=0 Message-ID: results for db9fe49069ed on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogUaLELI', '-x'] From python-checkins at python.org Mon Jul 15 10:05:10 2013 From: python-checkins at python.org (ronald.oussoren) Date: Mon, 15 Jul 2013 10:05:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Version_of_my_super_getattr_h?= =?utf-8?q?ook_proposal_as_posted_to_python-dev=2E?= Message-ID: <3bty2t5NtfzPCC@mail.python.org> http://hg.python.org/peps/rev/4e64c651ec3f changeset: 4997:4e64c651ec3f user: Ronald Oussoren date: Mon Jul 15 10:04:57 2013 +0200 summary: Version of my super getattr hook proposal as posted to python-dev. This will likely see significant changes based on feedback from Steve Dower. files: pep-0447.txt | 161 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 161 insertions(+), 0 deletions(-) diff --git a/pep-0447.txt b/pep-0447.txt new file mode 100644 --- /dev/null +++ b/pep-0447.txt @@ -0,0 +1,161 @@ +PEP: 447 +Title: Hooking into super attribute resolution +Version: $Revision$ +Last-Modified: $Date$ +Author: Ronald Oussoren +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 12-Jun-2013 +Post-History: 2-Jul-2013, ? + + +Abstract +======== + +In current python releases the attribute resolution of the `super class`_ +peeks in the ``__dict__`` attribute of classes on the MRO to look +for attributes. This PEP introduces a hook that classes can use +to override that behavior for specific classes. + + +Rationale +========= + +Peeking in the class ``__dict__`` works for regular classes, but can +cause problems when a class dynamicly looks up attributes in a +``__getattribute__`` method. + +The new hook makes it possible to introduce the same customization for +attribute lookup through the `super class`_. + + +The superclass attribute lookup hook +==================================== + +In C code +--------- + +A new slot ``tp_getattro_super`` is added to the ``PyTypeObject`` struct. The +``tp_getattro`` slot for super will call this slot when it is not ``NULL``, +and will raise an exception when it is not set (which shouldn't happen because +the method is implemented for :class:`object`). + +The slot has the following prototype:: + + PyObject* (*getattrosuperfunc)(PyTypeObject* cls, PyObject* name, + PyObject* object, PyObject* owner); + +The function should perform attribute lookup on *object* for *name*, but only +looking in type *tp* (which will be one of the types on the MRO for *self*) +and without looking in the instance *__dict__*. + +The function returns ``NULL`` when the attribute cannot be found, and raises and +exception. Exception other than ``AttributeError`` will cause failure of super's +attribute resolution. + +The implementation of the slot for the :class:`object` type is +``PyObject_GenericGetAttrSuper``, which peeks in the ``tp_dict`` for *cls*. + +Note that *owner* and *object* will be the same object when using a +class-mode super. + + +In Python code +-------------- + +A Python class can contain a definition for a static method +``__getattribute_super__`` with the following prototype:: + + def __getattribute_super__(cls, name, object, owner): pass + +The method should perform attribute lookup for *name* on instance *self* while +only looking at *cls* (it should not look in super classes or the instance +*__dict__* + +XXX: I haven't got a clue at the moment if the method should be an +instance-, class- or staticmethod. The prototype uses a staticmethod. + +XXX: My prototype automagicly makes this a static method, just like __new__ is +made into a static method. That's more convenient, but also (too?) magical. + +XXX: Should this raise AttributeError or return a magic value to signal that +an attribute cannot be found (such as NotImplemented, used in the comparison +operators)? I'm currently using an exception, a magical return value would +be slightly more efficient because the exception machinery is not invoked. + + +Alternative proposals +--------------------- + +Reuse ``tp_getattro`` +..................... + +It would be nice to avoid adding a new slot, thus keeping the API simpler and +easier to understand. A comment on `Issue 18181`_ asked about reusing the +``tp_getattro`` slot, that is super could call the ``tp_getattro`` slot of all +methods along the MRO. + +AFAIK that won't work because ``tp_getattro`` will look in the instance +``__dict__`` before it tries to resolve attributes using classes in the MRO. +This would mean that using ``tp_getattro`` instead of peeking the class +dictionaries changes the semantics of the `super class`_. + + +Open Issues +=========== + +* The names of the new slot and magic method are far from settled. + +* I'm not too happy with the prototype for the new hook. + +* Should ``__getattribute_super__`` be a class method instead? + + -> Yes? The method looks up a named attribute name of an object in + a specific class. Is also likely needed to deal with @classmethod + and super(Class, Class) + +* Should ``__getattribute_super__`` be defined on object? + + -> Yes: makes it easier to delegate to the default implementation + +* This doesn't necessarily work for class method super class + (e.g. super(object, object))... + + +References +========== + +* `Issue 18181`_ contains a prototype implementation + + The prototype uses different names than this proposal. + + +Copyright +========= + +This document has been placed in the public domain. + +.. _`Issue 18181`: http://bugs.python.org/issue18181 + +.. _`super class`: http://docs.python.org/3/library/functions.html?highlight=super#super + +Changes +======= + +* 3-jul-2013: + + + added note question about having object.__getattribute_super__ + + + added note about class super (super(Cls, Cls).classmethod) + + + changed to API for the python and C functions: + + - argument order + + - now a class method + + - added 'owner' argument (same as object.__get__) + + + added PyObject_GenericGetAttroSuper + -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 15 11:23:40 2013 From: python-checkins at python.org (ronald.oussoren) Date: Mon, 15 Jul 2013 11:23:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Rewrite_PEP_447_with_a_cleane?= =?utf-8?q?r_interface?= Message-ID: <3btznS4gmXz7LjQ@mail.python.org> http://hg.python.org/peps/rev/205119c61867 changeset: 4998:205119c61867 user: Ronald Oussoren date: Mon Jul 15 11:23:29 2013 +0200 summary: Rewrite PEP 447 with a cleaner interface This replaces a special method that was tuned for use by super() by one that is also usable for PyObject_GenericGetAttr, and has a cleaner interface (a method on the meta type instead of static method on the type that didn't really know what it wanted to be). Next up: provide prototype implementation, then post to python-dev again. files: pep-0447.txt | 157 +++++++++++++++++++------------------- 1 files changed, 79 insertions(+), 78 deletions(-) diff --git a/pep-0447.txt b/pep-0447.txt --- a/pep-0447.txt +++ b/pep-0447.txt @@ -26,68 +26,93 @@ cause problems when a class dynamicly looks up attributes in a ``__getattribute__`` method. -The new hook makes it possible to introduce the same customization for -attribute lookup through the `super class`_. +This new hook makes it possible to affect attribute lookup for both normal +attribute lookup and lookup through the `super class`_. The superclass attribute lookup hook ==================================== -In C code ---------- - -A new slot ``tp_getattro_super`` is added to the ``PyTypeObject`` struct. The -``tp_getattro`` slot for super will call this slot when it is not ``NULL``, -and will raise an exception when it is not set (which shouldn't happen because -the method is implemented for :class:`object`). - -The slot has the following prototype:: - - PyObject* (*getattrosuperfunc)(PyTypeObject* cls, PyObject* name, - PyObject* object, PyObject* owner); - -The function should perform attribute lookup on *object* for *name*, but only -looking in type *tp* (which will be one of the types on the MRO for *self*) -and without looking in the instance *__dict__*. - -The function returns ``NULL`` when the attribute cannot be found, and raises and -exception. Exception other than ``AttributeError`` will cause failure of super's -attribute resolution. - -The implementation of the slot for the :class:`object` type is -``PyObject_GenericGetAttrSuper``, which peeks in the ``tp_dict`` for *cls*. - -Note that *owner* and *object* will be the same object when using a -class-mode super. - +Both ``super.__getattribute__`` and ``object.__getattribute__`` (or +`PyObject_GenericGetAttr`_ in C code) walk an object's MRO and peek in the +class' ``__dict__`` to look up attributes. A way to affect this lookup is +using a method on the meta class for the type, that by default looks up +the name in the class ``__dict__``. In Python code -------------- -A Python class can contain a definition for a static method -``__getattribute_super__`` with the following prototype:: +A meta type can define a method ``__locallookup__`` that is called during +attribute resolution by both ``super.__getattribute__`` and ``object.__getattribute``:: - def __getattribute_super__(cls, name, object, owner): pass + class MetaType (type): -The method should perform attribute lookup for *name* on instance *self* while -only looking at *cls* (it should not look in super classes or the instance -*__dict__* + def __locallookup__(cls, name): + try: + return cls.__dict__[name] + except KeyError: + raise AttributeError(name) from None -XXX: I haven't got a clue at the moment if the method should be an -instance-, class- or staticmethod. The prototype uses a staticmethod. +The example method above is pseudo code for the implementation of this method on +`type`_ (the actual implementation is in C, and doesn't suffer from the recursion +problem in this example). -XXX: My prototype automagicly makes this a static method, just like __new__ is -made into a static method. That's more convenient, but also (too?) magical. +The ``__locallookup__`` method has as its arguments a class and the name of the attribute +that is looked up. It should return the value of the attribute without invoking descriptors, +or raise `AttributeError`_ when the name cannot be found. -XXX: Should this raise AttributeError or return a magic value to signal that -an attribute cannot be found (such as NotImplemented, used in the comparison -operators)? I'm currently using an exception, a magical return value would -be slightly more efficient because the exception machinery is not invoked. + +In C code +--------- + +A new slot ``tp_locallookup`` is added to the ``PyTypeObject`` struct, this slot +corresponds to the ``__locallookup__`` method on `type`_. + +The slot has the following prototype:: + + PyObject* (*locallookupfunc)(PyTypeObject* cls, PyObject* name); + +This method should lookup *name* in the namespace of *cls*, without looking at superclasses, +and should not invoke descriptors. The method returns ``NULL`` without setting an exception +when the *name* cannot be found, and returns a new reference otherwise (not a borrowed reference). + + +Usage of this hook +------------------ + +The new method will be defined for `type`_, and will peek in the class dictionary:: + + static PyObject* + type_locallookup(PyTypeObject* cls, PyObject* name) + { + PyObject* res; + if (!cls->tp_dict) { + return NULL; + } + + res = PyDict_GetItem(cls, name); + Py_XINCREF(res); + return res; + } + +The new method will be used by both `PyObject_GenericGetAttr`_ and +``super.__getattribute__`` instead of peeking in a type's ``tp_dict``. Alternative proposals --------------------- +``__getattribute_super__`` +.......................... + +An earlier version of this PEP used the following static method on classes:: + + def __getattribute_super__(cls, name, object, owner): pass + +This method performed name lookup as well as invoking descriptors and was necessarily +limited to working only with ``super.__getattribute__``. + + Reuse ``tp_getattro`` ..................... @@ -96,7 +121,7 @@ ``tp_getattro`` slot, that is super could call the ``tp_getattro`` slot of all methods along the MRO. -AFAIK that won't work because ``tp_getattro`` will look in the instance +That won't work because ``tp_getattro`` will look in the instance ``__dict__`` before it tries to resolve attributes using classes in the MRO. This would mean that using ``tp_getattro`` instead of peeking the class dictionaries changes the semantics of the `super class`_. @@ -107,28 +132,16 @@ * The names of the new slot and magic method are far from settled. -* I'm not too happy with the prototype for the new hook. - -* Should ``__getattribute_super__`` be a class method instead? - - -> Yes? The method looks up a named attribute name of an object in - a specific class. Is also likely needed to deal with @classmethod - and super(Class, Class) - -* Should ``__getattribute_super__`` be defined on object? - - -> Yes: makes it easier to delegate to the default implementation - -* This doesn't necessarily work for class method super class - (e.g. super(object, object))... +* Should the python method raise an exception or return a magic value (such as the + `NotImplemented`_ return value used by comparison operators). The latter could be + slightly faster because it doesn't have to overhead of setting up exception state, but + makes it impossible to use that value as an attribute on a class. References ========== -* `Issue 18181`_ contains a prototype implementation - - The prototype uses different names than this proposal. +* `Issue 18181`_ contains a prototype implementation (for an older version of this proposal) Copyright @@ -138,24 +151,12 @@ .. _`Issue 18181`: http://bugs.python.org/issue18181 -.. _`super class`: http://docs.python.org/3/library/functions.html?highlight=super#super +.. _`super class`: http://docs.python.org/3/library/functions.html#super -Changes -======= +.. _`NotImplemented`: http://docs.python.org/3/library/constants.html#NotImplemented -* 3-jul-2013: +.. _`PyObject_GenericGetAttr`: http://docs.python.org/3/c-api/object.html#PyObject_GenericGetAttr - + added note question about having object.__getattribute_super__ +.. _`type`: http://docs.python.org/3/library/functions.html#type - + added note about class super (super(Cls, Cls).classmethod) - - + changed to API for the python and C functions: - - - argument order - - - now a class method - - - added 'owner' argument (same as object.__get__) - - + added PyObject_GenericGetAttroSuper - +.. _`AttributeError`: http://docs.python.org/3/library/exceptions.html#AttributeError -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 15 11:40:03 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 15 Jul 2013 11:40:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDQ5?= =?utf-8?q?=3A_Make_Tools/demo/ss1=2Epy_work_again_on_Python_3=2E__Patch_b?= =?utf-8?q?y?= Message-ID: <3bv08M5PD3z7LjP@mail.python.org> http://hg.python.org/cpython/rev/a7b5e9ca8eee changeset: 84627:a7b5e9ca8eee branch: 3.3 parent: 84625:1a93c624551f user: Serhiy Storchaka date: Mon Jul 15 12:34:17 2013 +0300 summary: Issue #18449: Make Tools/demo/ss1.py work again on Python 3. Patch by F?vry Thibault. files: Misc/ACKS | 1 + Misc/NEWS | 3 +++ Tools/demo/ss1.py | 28 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1213,6 +1213,7 @@ Mikhail Terekhov Richard M. Tew Tobias Thelen +F?vry Thibault Lowe Thiderman Nicolas M. Thi?ry James Thomas diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -221,6 +221,9 @@ Tools/Demos ----------- +- Issue #18449: Make Tools/demo/ss1.py work again on Python 3. Patch by + F?vry Thibault. + - Issue #15239: Make mkstringprep.py work again on Python 3. - Issue #12990: The "Python Launcher" on OSX could not launch python scripts diff --git a/Tools/demo/ss1.py b/Tools/demo/ss1.py --- a/Tools/demo/ss1.py +++ b/Tools/demo/ss1.py @@ -79,10 +79,10 @@ del self.cells[xy] def clearrows(self, y1, y2): - self.clearcells(0, y1, sys.maxint, y2) + self.clearcells(0, y1, sys.maxsize, y2) def clearcolumns(self, x1, x2): - self.clearcells(x1, 0, x2, sys.maxint) + self.clearcells(x1, 0, x2, sys.maxsize) def selectcells(self, x1, y1, x2, y2): if x1 > x2: @@ -113,23 +113,23 @@ def insertrows(self, y, n): assert n > 0 - self.movecells(0, y, sys.maxint, sys.maxint, 0, n) + self.movecells(0, y, sys.maxsize, sys.maxsize, 0, n) def deleterows(self, y1, y2): if y1 > y2: y1, y2 = y2, y1 self.clearrows(y1, y2) - self.movecells(0, y2+1, sys.maxint, sys.maxint, 0, y1-y2-1) + self.movecells(0, y2+1, sys.maxsize, sys.maxsize, 0, y1-y2-1) def insertcolumns(self, x, n): assert n > 0 - self.movecells(x, 0, sys.maxint, sys.maxint, n, 0) + self.movecells(x, 0, sys.maxsize, sys.maxsize, n, 0) def deletecolumns(self, x1, x2): if x1 > x2: x1, x2 = x2, x1 self.clearcells(x1, x2) - self.movecells(x2+1, 0, sys.maxint, sys.maxint, x1-x2-1, 0) + self.movecells(x2+1, 0, sys.maxsize, sys.maxsize, x1-x2-1, 0) def getsize(self): maxx = maxy = 0 @@ -626,29 +626,29 @@ def selectall(self, event): self.setcurrent(1, 1) - self.setcorner(sys.maxint, sys.maxint) + self.setcorner(sys.maxsize, sys.maxsize) def selectcolumn(self, event): x, y = self.whichxy(event) self.setcurrent(x, 1) - self.setcorner(x, sys.maxint) + self.setcorner(x, sys.maxsize) def extendcolumn(self, event): x, y = self.whichxy(event) if x > 0: self.setcurrent(self.currentxy[0], 1) - self.setcorner(x, sys.maxint) + self.setcorner(x, sys.maxsize) def selectrow(self, event): x, y = self.whichxy(event) self.setcurrent(1, y) - self.setcorner(sys.maxint, y) + self.setcorner(sys.maxsize, y) def extendrow(self, event): x, y = self.whichxy(event) if y > 0: self.setcurrent(1, self.currentxy[1]) - self.setcorner(sys.maxint, y) + self.setcorner(sys.maxsize, y) def press(self, event): x, y = self.whichxy(event) @@ -709,14 +709,14 @@ self.setbeacon(x1, y1, x2, y2) def setbeacon(self, x1, y1, x2, y2): - if x1 == y1 == 1 and x2 == y2 == sys.maxint: + if x1 == y1 == 1 and x2 == y2 == sys.maxsize: name = ":" - elif (x1, x2) == (1, sys.maxint): + elif (x1, x2) == (1, sys.maxsize): if y1 == y2: name = "%d" % y1 else: name = "%d:%d" % (y1, y2) - elif (y1, y2) == (1, sys.maxint): + elif (y1, y2) == (1, sys.maxsize): if x1 == x2: name = "%s" % colnum2name(x1) else: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 11:40:05 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 15 Jul 2013 11:40:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318449=3A_Make_Tools/demo/ss1=2Epy_work_again_on?= =?utf-8?q?_Python_3=2E__Patch_by?= Message-ID: <3bv08P1Xpsz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/34333dab3ac4 changeset: 84628:34333dab3ac4 parent: 84626:db9fe49069ed parent: 84627:a7b5e9ca8eee user: Serhiy Storchaka date: Mon Jul 15 12:37:43 2013 +0300 summary: Issue #18449: Make Tools/demo/ss1.py work again on Python 3. Patch by F?vry Thibault. files: Misc/ACKS | 1 + Misc/NEWS | 3 +++ Tools/demo/ss1.py | 28 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1248,6 +1248,7 @@ Victor Terr?n Richard M. Tew Tobias Thelen +F?vry Thibault Lowe Thiderman Nicolas M. Thi?ry James Thomas diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -656,6 +656,9 @@ Tools/Demos ----------- +- Issue #18449: Make Tools/demo/ss1.py work again on Python 3. Patch by + F?vry Thibault. + - Issue #12990: The "Python Launcher" on OSX could not launch python scripts that have paths that include wide characters. diff --git a/Tools/demo/ss1.py b/Tools/demo/ss1.py --- a/Tools/demo/ss1.py +++ b/Tools/demo/ss1.py @@ -79,10 +79,10 @@ del self.cells[xy] def clearrows(self, y1, y2): - self.clearcells(0, y1, sys.maxint, y2) + self.clearcells(0, y1, sys.maxsize, y2) def clearcolumns(self, x1, x2): - self.clearcells(x1, 0, x2, sys.maxint) + self.clearcells(x1, 0, x2, sys.maxsize) def selectcells(self, x1, y1, x2, y2): if x1 > x2: @@ -113,23 +113,23 @@ def insertrows(self, y, n): assert n > 0 - self.movecells(0, y, sys.maxint, sys.maxint, 0, n) + self.movecells(0, y, sys.maxsize, sys.maxsize, 0, n) def deleterows(self, y1, y2): if y1 > y2: y1, y2 = y2, y1 self.clearrows(y1, y2) - self.movecells(0, y2+1, sys.maxint, sys.maxint, 0, y1-y2-1) + self.movecells(0, y2+1, sys.maxsize, sys.maxsize, 0, y1-y2-1) def insertcolumns(self, x, n): assert n > 0 - self.movecells(x, 0, sys.maxint, sys.maxint, n, 0) + self.movecells(x, 0, sys.maxsize, sys.maxsize, n, 0) def deletecolumns(self, x1, x2): if x1 > x2: x1, x2 = x2, x1 self.clearcells(x1, x2) - self.movecells(x2+1, 0, sys.maxint, sys.maxint, x1-x2-1, 0) + self.movecells(x2+1, 0, sys.maxsize, sys.maxsize, x1-x2-1, 0) def getsize(self): maxx = maxy = 0 @@ -626,29 +626,29 @@ def selectall(self, event): self.setcurrent(1, 1) - self.setcorner(sys.maxint, sys.maxint) + self.setcorner(sys.maxsize, sys.maxsize) def selectcolumn(self, event): x, y = self.whichxy(event) self.setcurrent(x, 1) - self.setcorner(x, sys.maxint) + self.setcorner(x, sys.maxsize) def extendcolumn(self, event): x, y = self.whichxy(event) if x > 0: self.setcurrent(self.currentxy[0], 1) - self.setcorner(x, sys.maxint) + self.setcorner(x, sys.maxsize) def selectrow(self, event): x, y = self.whichxy(event) self.setcurrent(1, y) - self.setcorner(sys.maxint, y) + self.setcorner(sys.maxsize, y) def extendrow(self, event): x, y = self.whichxy(event) if y > 0: self.setcurrent(1, self.currentxy[1]) - self.setcorner(sys.maxint, y) + self.setcorner(sys.maxsize, y) def press(self, event): x, y = self.whichxy(event) @@ -709,14 +709,14 @@ self.setbeacon(x1, y1, x2, y2) def setbeacon(self, x1, y1, x2, y2): - if x1 == y1 == 1 and x2 == y2 == sys.maxint: + if x1 == y1 == 1 and x2 == y2 == sys.maxsize: name = ":" - elif (x1, x2) == (1, sys.maxint): + elif (x1, x2) == (1, sys.maxsize): if y1 == y2: name = "%d" % y1 else: name = "%d:%d" % (y1, y2) - elif (y1, y2) == (1, sys.maxint): + elif (y1, y2) == (1, sys.maxsize): if x1 == x2: name = "%s" % colnum2name(x1) else: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 13:13:31 2013 From: python-checkins at python.org (nick.coghlan) Date: Mon, 15 Jul 2013 13:13:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_issue_17482=3A_don?= =?utf-8?b?J3Qgb3ZlcndyaXRlIF9fd3JhcHBlZF9f?= Message-ID: <3bv2DC3h3tz7LnS@mail.python.org> http://hg.python.org/cpython/rev/13b8fd71db46 changeset: 84629:13b8fd71db46 user: Nick Coghlan date: Mon Jul 15 21:13:08 2013 +1000 summary: Close issue 17482: don't overwrite __wrapped__ files: Doc/library/functools.rst | 9 +++++++-- Doc/whatsnew/3.4.rst | 9 +++++++++ Lib/functools.py | 4 +++- Lib/test/test_functools.py | 14 +++++++++++--- Misc/NEWS | 4 ++++ 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -306,8 +306,8 @@ To allow access to the original function for introspection and other purposes (e.g. bypassing a caching decorator such as :func:`lru_cache`), this function - automatically adds a __wrapped__ attribute to the wrapper that refers to - the original function. + automatically adds a ``__wrapped__`` attribute to the wrapper that refers to + the function being wrapped. The main intended use for this function is in :term:`decorator` functions which wrap the decorated function and return the wrapper. If the wrapper function is @@ -330,6 +330,11 @@ .. versionchanged:: 3.2 Missing attributes no longer trigger an :exc:`AttributeError`. + .. versionchanged:: 3.4 + The ``__wrapped__`` attribute now always refers to the wrapped + function, even if that function defined a ``__wrapped__`` attribute. + (see :issue:`17482`) + .. decorator:: wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES) 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 @@ -315,3 +315,12 @@ found but improperly structured. If you were catching ImportError before and wish to continue to ignore syntax or decoding issues, catch all three exceptions now. + +* :func:`functools.update_wrapper` and :func:`functools.wraps` now correctly + set the ``__wrapped__`` attribute even if the wrapped function had a + wrapped attribute set. This means ``__wrapped__`` attributes now correctly + link a stack of decorated functions rather than every ``__wrapped__`` + attribute in the chain referring to the innermost function. Introspection + libraries that assumed the previous behaviour was intentional will need to + be updated to walk the chain of ``__wrapped__`` attributes to find the + innermost function. diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -55,7 +55,6 @@ are updated with the corresponding attribute from the wrapped function (defaults to functools.WRAPPER_UPDATES) """ - wrapper.__wrapped__ = wrapped for attr in assigned: try: value = getattr(wrapped, attr) @@ -65,6 +64,9 @@ setattr(wrapper, attr, value) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + # Issue #17482: set __wrapped__ last so we don't inadvertently copy it + # from the wrapped function when updating __dict__ + wrapper.__wrapped__ = wrapped # Return the wrapper so this can be used as a decorator via partial() return wrapper diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -224,19 +224,26 @@ updated=functools.WRAPPER_UPDATES): # Check attributes were assigned for name in assigned: - self.assertTrue(getattr(wrapper, name) is getattr(wrapped, name)) + self.assertIs(getattr(wrapper, name), getattr(wrapped, name)) # Check attributes were updated for name in updated: wrapper_attr = getattr(wrapper, name) wrapped_attr = getattr(wrapped, name) for key in wrapped_attr: - self.assertTrue(wrapped_attr[key] is wrapper_attr[key]) + if name == "__dict__" and key == "__wrapped__": + # __wrapped__ is overwritten by the update code + continue + self.assertIs(wrapped_attr[key], wrapper_attr[key]) + # Check __wrapped__ + self.assertIs(wrapper.__wrapped__, wrapped) + def _default_update(self): def f(a:'This is a new annotation'): """This is a test""" pass f.attr = 'This is also a test' + f.__wrapped__ = "This is a bald faced lie" def wrapper(b:'This is the prior annotation'): pass functools.update_wrapper(wrapper, f) @@ -331,14 +338,15 @@ """This is a test""" pass f.attr = 'This is also a test' + f.__wrapped__ = "This is still a bald faced lie" @functools.wraps(f) def wrapper(): pass - self.check_wrapper(wrapper, f) return wrapper, f def test_default_update(self): wrapper, f = self._default_update() + self.check_wrapper(wrapper, f) self.assertEqual(wrapper.__name__, 'f') self.assertEqual(wrapper.__qualname__, f.__qualname__) self.assertEqual(wrapper.attr, 'This is also a test') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -154,6 +154,10 @@ Library ------- +- Issue #17482: functools.update_wrapper (and functools.wraps) now set the + __wrapped__ attribute correctly even if the underlying function has a + __wrapped__ attribute set. + - Issue #18431: The new email header parser now decodes RFC2047 encoded words in structured headers. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 17:10:27 2013 From: python-checkins at python.org (ronald.oussoren) Date: Mon, 15 Jul 2013 17:10:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Document_a_possible_attribute?= =?utf-8?q?_cache_issue_with_the_proposed_changes_to?= Message-ID: <3bv7Tb2l4Zz7LjN@mail.python.org> http://hg.python.org/peps/rev/ff25a6347a2e changeset: 4999:ff25a6347a2e user: Ronald Oussoren date: Mon Jul 15 17:10:15 2013 +0200 summary: Document a possible attribute cache issue with the proposed changes to PyObject_GenericGetAttr files: pep-0447.txt | 13 ++++++++++++- 1 files changed, 12 insertions(+), 1 deletions(-) diff --git a/pep-0447.txt b/pep-0447.txt --- a/pep-0447.txt +++ b/pep-0447.txt @@ -7,7 +7,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 12-Jun-2013 -Post-History: 2-Jul-2013, ? +Post-History: 2-Jul-2013, 15-Jul-2013 Abstract @@ -137,6 +137,17 @@ slightly faster because it doesn't have to overhead of setting up exception state, but makes it impossible to use that value as an attribute on a class. +* The proposed change to `PyObject_GenericGetAttr`_ will probably cause problems with the + attribute lookup cache (MCACHE): + + 1. That code stores borrowed references, which won't work when the hook is present. That + is mostly fixable, but at the cost of possibly keeping garbage alive. + + 2. Caching isn't an option when a hook might execute arbitrary code (and there hence is + no reason to assume that the hooks return value won't change later on). + + The only workaround I could find for this is to make the hook a fallback (that is, + more like ``__getattr__`` than ``__getattribute__``). References ========== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 15 17:11:30 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 15 Jul 2013 17:11:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MzQ0?= =?utf-8?q?=3A_Fix_potential_ref-leaks_in_=5Fbufferedreader=5Fread=5Fall?= =?utf-8?b?KCku?= Message-ID: <3bv7Vp4NwTz7LjN@mail.python.org> http://hg.python.org/cpython/rev/9ce863993a38 changeset: 84630:9ce863993a38 branch: 3.3 parent: 84627:a7b5e9ca8eee user: Richard Oudkerk date: Mon Jul 15 16:05:22 2013 +0100 summary: Issue #18344: Fix potential ref-leaks in _bufferedreader_read_all(). files: Misc/NEWS | 2 + Modules/_io/bufferedio.c | 93 +++++++++++++-------------- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,8 @@ Core and Builtins ----------------- +- Issue #18344: Fix potential ref-leaks in _bufferedreader_read_all(). + - Issue #17872: Fix a segfault in marshal.load() when input stream returns more bytes than requested. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1474,7 +1474,7 @@ _bufferedreader_read_all(buffered *self) { Py_ssize_t current_size; - PyObject *res, *data = NULL, *chunk, *chunks; + PyObject *res = NULL, *data = NULL, *tmp = NULL, *chunks = NULL; /* First copy what we have in the current buffer. */ current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); @@ -1487,85 +1487,82 @@ } /* We're going past the buffer's bounds, flush it */ if (self->writable) { - res = buffered_flush_and_rewind_unlocked(self); - if (res == NULL) - return NULL; - Py_CLEAR(res); + tmp = buffered_flush_and_rewind_unlocked(self); + if (tmp == NULL) + goto cleanup; + Py_CLEAR(tmp); } _bufferedreader_reset_buf(self); if (PyObject_HasAttr(self->raw, _PyIO_str_readall)) { - chunk = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readall, NULL); - if (chunk == NULL) - return NULL; - if (chunk != Py_None && !PyBytes_Check(chunk)) { - Py_XDECREF(data); - Py_DECREF(chunk); + tmp = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readall, NULL); + if (tmp == NULL) + goto cleanup; + if (tmp != Py_None && !PyBytes_Check(tmp)) { PyErr_SetString(PyExc_TypeError, "readall() should return bytes"); - return NULL; + goto cleanup; } - if (chunk == Py_None) { - if (current_size == 0) - return chunk; - else { - Py_DECREF(chunk); - return data; + if (tmp == Py_None) { + if (current_size == 0) { + res = Py_None; + goto cleanup; + } else { + res = data; + goto cleanup; } } else if (current_size) { - PyBytes_Concat(&data, chunk); - Py_DECREF(chunk); - if (data == NULL) - return NULL; - return data; - } else - return chunk; + PyBytes_Concat(&data, tmp); + res = data; + goto cleanup; + } + else { + res = tmp; + goto cleanup; + } } chunks = PyList_New(0); - if (chunks == NULL) { - Py_XDECREF(data); - return NULL; - } + if (chunks == NULL) + goto cleanup; while (1) { if (data) { - if (PyList_Append(chunks, data) < 0) { - Py_DECREF(data); - Py_DECREF(chunks); - return NULL; - } - Py_DECREF(data); + if (PyList_Append(chunks, data) < 0) + goto cleanup; + Py_CLEAR(data); } /* Read until EOF or until read() would block. */ data = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_read, NULL); - if (data == NULL) { - Py_DECREF(chunks); - return NULL; - } + if (data == NULL) + goto cleanup; if (data != Py_None && !PyBytes_Check(data)) { - Py_DECREF(data); - Py_DECREF(chunks); PyErr_SetString(PyExc_TypeError, "read() should return bytes"); - return NULL; + goto cleanup; } if (data == Py_None || PyBytes_GET_SIZE(data) == 0) { if (current_size == 0) { - Py_DECREF(chunks); - return data; + res = data; + goto cleanup; } else { - res = _PyBytes_Join(_PyIO_empty_bytes, chunks); - Py_DECREF(data); - Py_DECREF(chunks); - return res; + tmp = _PyBytes_Join(_PyIO_empty_bytes, chunks); + res = tmp; + goto cleanup; } } current_size += PyBytes_GET_SIZE(data); if (self->abs_pos != -1) self->abs_pos += PyBytes_GET_SIZE(data); } +cleanup: + /* res is either NULL or a borrowed ref */ + Py_XINCREF(res); + Py_XDECREF(data); + Py_XDECREF(tmp); + Py_XDECREF(chunks); + return res; } /* Read n bytes from the buffer if it can, otherwise return None. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 17:11:32 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 15 Jul 2013 17:11:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318344=3A_Fix_potential_ref-leaks_in_=5Fbuffered?= =?utf-8?b?cmVhZGVyX3JlYWRfYWxsKCku?= Message-ID: <3bv7Vr0VC1z7Lkt@mail.python.org> http://hg.python.org/cpython/rev/9b041f44cb63 changeset: 84631:9b041f44cb63 parent: 84629:13b8fd71db46 parent: 84630:9ce863993a38 user: Richard Oudkerk date: Mon Jul 15 16:10:28 2013 +0100 summary: Issue #18344: Fix potential ref-leaks in _bufferedreader_read_all(). files: Misc/NEWS | 2 + Modules/_io/bufferedio.c | 93 +++++++++++++-------------- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #18344: Fix potential ref-leaks in _bufferedreader_read_all(). + - Issue #18342: Use the repr of a module name when an import fails when using ``from ... import ...``. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1479,7 +1479,7 @@ _bufferedreader_read_all(buffered *self) { Py_ssize_t current_size; - PyObject *res, *data = NULL, *chunk, *chunks; + PyObject *res = NULL, *data = NULL, *tmp = NULL, *chunks = NULL; /* First copy what we have in the current buffer. */ current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); @@ -1492,85 +1492,82 @@ } /* We're going past the buffer's bounds, flush it */ if (self->writable) { - res = buffered_flush_and_rewind_unlocked(self); - if (res == NULL) - return NULL; - Py_CLEAR(res); + tmp = buffered_flush_and_rewind_unlocked(self); + if (tmp == NULL) + goto cleanup; + Py_CLEAR(tmp); } _bufferedreader_reset_buf(self); if (PyObject_HasAttr(self->raw, _PyIO_str_readall)) { - chunk = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readall, NULL); - if (chunk == NULL) - return NULL; - if (chunk != Py_None && !PyBytes_Check(chunk)) { - Py_XDECREF(data); - Py_DECREF(chunk); + tmp = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readall, NULL); + if (tmp == NULL) + goto cleanup; + if (tmp != Py_None && !PyBytes_Check(tmp)) { PyErr_SetString(PyExc_TypeError, "readall() should return bytes"); - return NULL; + goto cleanup; } - if (chunk == Py_None) { - if (current_size == 0) - return chunk; - else { - Py_DECREF(chunk); - return data; + if (tmp == Py_None) { + if (current_size == 0) { + res = Py_None; + goto cleanup; + } else { + res = data; + goto cleanup; } } else if (current_size) { - PyBytes_Concat(&data, chunk); - Py_DECREF(chunk); - if (data == NULL) - return NULL; - return data; - } else - return chunk; + PyBytes_Concat(&data, tmp); + res = data; + goto cleanup; + } + else { + res = tmp; + goto cleanup; + } } chunks = PyList_New(0); - if (chunks == NULL) { - Py_XDECREF(data); - return NULL; - } + if (chunks == NULL) + goto cleanup; while (1) { if (data) { - if (PyList_Append(chunks, data) < 0) { - Py_DECREF(data); - Py_DECREF(chunks); - return NULL; - } - Py_DECREF(data); + if (PyList_Append(chunks, data) < 0) + goto cleanup; + Py_CLEAR(data); } /* Read until EOF or until read() would block. */ data = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_read, NULL); - if (data == NULL) { - Py_DECREF(chunks); - return NULL; - } + if (data == NULL) + goto cleanup; if (data != Py_None && !PyBytes_Check(data)) { - Py_DECREF(data); - Py_DECREF(chunks); PyErr_SetString(PyExc_TypeError, "read() should return bytes"); - return NULL; + goto cleanup; } if (data == Py_None || PyBytes_GET_SIZE(data) == 0) { if (current_size == 0) { - Py_DECREF(chunks); - return data; + res = data; + goto cleanup; } else { - res = _PyBytes_Join(_PyIO_empty_bytes, chunks); - Py_DECREF(data); - Py_DECREF(chunks); - return res; + tmp = _PyBytes_Join(_PyIO_empty_bytes, chunks); + res = tmp; + goto cleanup; } } current_size += PyBytes_GET_SIZE(data); if (self->abs_pos != -1) self->abs_pos += PyBytes_GET_SIZE(data); } +cleanup: + /* res is either NULL or a borrowed ref */ + Py_XINCREF(res); + Py_XDECREF(data); + Py_XDECREF(tmp); + Py_XDECREF(chunks); + return res; } /* Read n bytes from the buffer if it can, otherwise return None. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 17:12:45 2013 From: python-checkins at python.org (ronald.oussoren) Date: Mon, 15 Jul 2013 17:12:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_There_is_implementation_of_th?= =?utf-8?q?e_super=28=29_changes_in_this_PEP=2E?= Message-ID: <3bv7XF4slrz7LjN@mail.python.org> http://hg.python.org/peps/rev/f589d4509a1e changeset: 5000:f589d4509a1e user: Ronald Oussoren date: Mon Jul 15 17:12:32 2013 +0200 summary: There is implementation of the super() changes in this PEP. files: pep-0447.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0447.txt b/pep-0447.txt --- a/pep-0447.txt +++ b/pep-0447.txt @@ -152,7 +152,7 @@ References ========== -* `Issue 18181`_ contains a prototype implementation (for an older version of this proposal) +* `Issue 18181`_ contains a partial prototype implementation Copyright -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 15 18:10:41 2013 From: python-checkins at python.org (r.david.murray) Date: Mon, 15 Jul 2013 18:10:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogQ2xvc2VzICMxODQ2?= =?utf-8?q?4=3A_fix_typo_in_test_name=2E?= Message-ID: <3bv8q51sRyz7LkJ@mail.python.org> http://hg.python.org/cpython/rev/6a6ca7c49c2a changeset: 84632:6a6ca7c49c2a branch: 3.3 parent: 84630:9ce863993a38 user: R David Murray date: Mon Jul 15 12:09:47 2013 -0400 summary: Closes #18464: fix typo in test name. files: Lib/test/test_email/test__encoded_words.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_email/test__encoded_words.py b/Lib/test/test_email/test__encoded_words.py --- a/Lib/test/test_email/test__encoded_words.py +++ b/Lib/test/test_email/test__encoded_words.py @@ -75,7 +75,7 @@ def test_non_trivial_q(self): self._test('=?latin-1?q?=20F=fcr=20Elise=20?=', ' F?r Elise ', 'latin-1') - def test_q_escpaed_bytes_preserved(self): + def test_q_escaped_bytes_preserved(self): self._test(b'=?us-ascii?q?=20\xACfoo?='.decode('us-ascii', 'surrogateescape'), ' \uDCACfoo', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 18:10:42 2013 From: python-checkins at python.org (r.david.murray) Date: Mon, 15 Jul 2013 18:10:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_Closes_=2318464=3A_fix_typo_in_test_name=2E?= Message-ID: <3bv8q63kXwz7Lpj@mail.python.org> http://hg.python.org/cpython/rev/47a659bc11c4 changeset: 84633:47a659bc11c4 parent: 84631:9b041f44cb63 parent: 84632:6a6ca7c49c2a user: R David Murray date: Mon Jul 15 12:10:29 2013 -0400 summary: Merge: Closes #18464: fix typo in test name. files: Lib/test/test_email/test__encoded_words.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_email/test__encoded_words.py b/Lib/test/test_email/test__encoded_words.py --- a/Lib/test/test_email/test__encoded_words.py +++ b/Lib/test/test_email/test__encoded_words.py @@ -75,7 +75,7 @@ def test_non_trivial_q(self): self._test('=?latin-1?q?=20F=fcr=20Elise=20?=', ' F?r Elise ', 'latin-1') - def test_q_escpaed_bytes_preserved(self): + def test_q_escaped_bytes_preserved(self): self._test(b'=?us-ascii?q?=20\xACfoo?='.decode('us-ascii', 'surrogateescape'), ' \uDCACfoo', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 18:32:24 2013 From: python-checkins at python.org (ronald.oussoren) Date: Mon, 15 Jul 2013 18:32:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318393=3A_Remove_u?= =?utf-8?q?se_of_deprecated_API_on_OSX?= Message-ID: <3bv9J80Cjxz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/ccbaf6762b54 changeset: 84634:ccbaf6762b54 user: Ronald Oussoren date: Mon Jul 15 18:32:09 2013 +0200 summary: Issue #18393: Remove use of deprecated API on OSX The "Gestalt" function on OSX is deprecated (starting with OSX 10.8), remove its usage from the stdlib. The patch removes a number of private functions and a private module, but does not change the public API. The removed code was effectively dead, the platform module has used other code to fetch the OSX version for years and could only use on the Gestalt-based code as a fallback. That fallback can only trigger on broken OSX installs (that is, someone has removed parts of the system install) files: Lib/platform.py | 64 +------------------------- Misc/NEWS | 4 + Modules/_gestalt.c | 84 ---------------------------------- setup.py | 4 - 4 files changed, 5 insertions(+), 151 deletions(-) diff --git a/Lib/platform.py b/Lib/platform.py --- a/Lib/platform.py +++ b/Lib/platform.py @@ -634,62 +634,6 @@ RegCloseKey(keyCurVer) return release,version,csd,ptype -def _mac_ver_lookup(selectors,default=None): - - from _gestalt import gestalt - l = [] - append = l.append - for selector in selectors: - try: - append(gestalt(selector)) - except (RuntimeError, OSError): - append(default) - return l - -def _bcd2str(bcd): - - return hex(bcd)[2:] - -def _mac_ver_gestalt(): - """ - Thanks to Mark R. Levinson for mailing documentation links and - code examples for this function. Documentation for the - gestalt() API is available online at: - - http://www.rgaros.nl/gestalt/ - """ - # Check whether the version info module is available - try: - import _gestalt - except ImportError: - return None - # Get the infos - sysv, sysa = _mac_ver_lookup(('sysv','sysa')) - # Decode the infos - if sysv: - major = (sysv & 0xFF00) >> 8 - minor = (sysv & 0x00F0) >> 4 - patch = (sysv & 0x000F) - - if (major, minor) >= (10, 4): - # the 'sysv' gestald cannot return patchlevels - # higher than 9. Apple introduced 3 new - # gestalt codes in 10.4 to deal with this - # issue (needed because patch levels can - # run higher than 9, such as 10.4.11) - major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3')) - release = '%i.%i.%i' %(major, minor, patch) - else: - release = '%s.%i.%i' % (_bcd2str(major),minor,patch) - - if sysa: - machine = {0x1: '68k', - 0x2: 'PowerPC', - 0xa: 'i386'}.get(sysa,'') - - versioninfo=('', '', '') - return release,versioninfo,machine - def _mac_ver_xml(): fn = '/System/Library/CoreServices/SystemVersion.plist' if not os.path.exists(fn): @@ -705,7 +649,7 @@ versioninfo=('', '', '') machine = os.uname().machine if machine in ('ppc', 'Power Macintosh'): - # for compatibility with the gestalt based code + # Cannonical name machine = 'PowerPC' return release,versioninfo,machine @@ -727,12 +671,6 @@ if info is not None: return info - # If that doesn't work for some reason fall back to reading the - # information using gestalt calls. - info = _mac_ver_gestalt() - if info is not None: - return info - # If that also doesn't work return the default values return release,versioninfo,machine diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -156,6 +156,10 @@ Library ------- +- Issue #18393: The private module _gestalt and private functions platform._mac_ver_gestalt, + platform._mac_ver_lookup and platform._bcd2str have been removed. This does not + affect the public interface of the platform module. + - Issue #17482: functools.update_wrapper (and functools.wraps) now set the __wrapped__ attribute correctly even if the underlying function has a __wrapped__ attribute set. diff --git a/Modules/_gestalt.c b/Modules/_gestalt.c deleted file mode 100644 --- a/Modules/_gestalt.c +++ /dev/null @@ -1,84 +0,0 @@ -/*********************************************************** -Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam, -The Netherlands. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the names of Stichting Mathematisch -Centrum or CWI not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior permission. - -STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -******************************************************************/ - -/* Macintosh Gestalt interface */ - -#include "Python.h" - -#include - -/* Convert a 4-char string object argument to an OSType value */ -static int -convert_to_OSType(PyObject *v, OSType *pr) -{ - uint32_t tmp; - if (!PyUnicode_Check(v) || PyUnicode_GetLength(v) != 4) { - PyErr_SetString(PyExc_TypeError, - "OSType arg must be string of 4 chars"); - return 0; - } - memcpy((char *)&tmp, _PyUnicode_AsString(v), 4); - *pr = (OSType)ntohl(tmp); - return 1; -} - -static PyObject * -gestalt_gestalt(PyObject *self, PyObject *args) -{ - OSErr iErr; - OSType selector; - SInt32 response; - if (!PyArg_ParseTuple(args, "O&", convert_to_OSType, &selector)) - return NULL; - iErr = Gestalt(selector, &response); - if (iErr != 0) { - PyErr_SetString(PyExc_OSError, - "non-zero exit code!"); - return NULL; - } - return PyLong_FromLong(response); -} - -static struct PyMethodDef gestalt_methods[] = { - {"gestalt", gestalt_gestalt, METH_VARARGS}, - {NULL, NULL} /* Sentinel */ -}; - -static struct PyModuleDef gestaltmodule = { - PyModuleDef_HEAD_INIT, - "_gestalt", - NULL, - -1, - gestalt_methods, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC -PyInit__gestalt(void) -{ - return PyModule_Create(&gestaltmodule); -} diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -1520,10 +1520,6 @@ if host_platform == 'darwin': exts.append( - Extension('_gestalt', ['_gestalt.c'], - extra_link_args=['-framework', 'Carbon']) - ) - exts.append( Extension('_scproxy', ['_scproxy.c'], extra_link_args=[ '-framework', 'SystemConfiguration', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 18:35:58 2013 From: python-checkins at python.org (ronald.oussoren) Date: Mon, 15 Jul 2013 18:35:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Move_entry_fro?= =?utf-8?q?m_=2318427_to_the_right_section_in_the_NEWS_file?= Message-ID: <3bv9NG2JjQz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/06d9f106c57e changeset: 84635:06d9f106c57e branch: 2.7 parent: 84624:8c935717fc8e user: Ronald Oussoren date: Mon Jul 15 18:35:14 2013 +0200 summary: Move entry from #18427 to the right section in the NEWS file 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 @@ -21,14 +21,14 @@ - Issue #18019: Fix crash in the repr of dictionaries containing their own views. +- Issue #18427: str.replace could crash the interpreter with huge strings. + Library ------- - Issue #18101: Tcl.split() now process Unicode strings nested in a tuple as it do with byte strings. -- Issue #18427: str.replace could crash the interpreter with huge strings. - - Issue #18347: ElementTree's html serializer now preserves the case of closing tags. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 18:37:32 2013 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 15 Jul 2013 18:37:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Fix_minor_grammatical/typogra?= =?utf-8?q?phical_issues=2E?= Message-ID: <3bv9Q43BW3z7Ljj@mail.python.org> http://hg.python.org/peps/rev/5f941ac83167 changeset: 5001:5f941ac83167 user: Guido van Rossum date: Mon Jul 15 09:37:26 2013 -0700 summary: Fix minor grammatical/typographical issues. files: pep-0447.txt | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0447.txt b/pep-0447.txt --- a/pep-0447.txt +++ b/pep-0447.txt @@ -23,7 +23,7 @@ ========= Peeking in the class ``__dict__`` works for regular classes, but can -cause problems when a class dynamicly looks up attributes in a +cause problems when a class dynamically looks up attributes in a ``__getattribute__`` method. This new hook makes it possible to affect attribute lookup for both normal @@ -45,7 +45,7 @@ A meta type can define a method ``__locallookup__`` that is called during attribute resolution by both ``super.__getattribute__`` and ``object.__getattribute``:: - class MetaType (type): + class MetaType(type): def __locallookup__(cls, name): try: @@ -53,7 +53,7 @@ except KeyError: raise AttributeError(name) from None -The example method above is pseudo code for the implementation of this method on +The example method above is pseudocode for the implementation of this method on `type`_ (the actual implementation is in C, and doesn't suffer from the recursion problem in this example). -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 15 19:39:07 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 15 Jul 2013 19:39:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDU1?= =?utf-8?q?=3A_multiprocessing_should_not_retry_connect=28=29_with_same_so?= =?utf-8?q?cket=2E?= Message-ID: <3bvBn70KSFz7LlX@mail.python.org> http://hg.python.org/cpython/rev/542a317d4351 changeset: 84636:542a317d4351 branch: 2.7 user: Richard Oudkerk date: Mon Jul 15 18:37:48 2013 +0100 summary: Issue #18455: multiprocessing should not retry connect() with same socket. files: Lib/multiprocessing/connection.py | 7 ++++--- Misc/NEWS | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -294,15 +294,16 @@ ''' Return a connection object connected to the socket given by `address` ''' - family = address_type(address) - s = socket.socket( getattr(socket, family) ) - s.setblocking(True) + family = getattr(socket, address_type(address)) t = _init_timeout() while 1: + s = socket.socket(family) + s.setblocking(True) try: s.connect(address) except socket.error, e: + s.close() if e.args[0] != errno.ECONNREFUSED or _check_timeout(t): debug('failed to connect to address %s', address) raise diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,6 +26,8 @@ Library ------- +- Issue #18455: multiprocessing should not retry connect() with same socket. + - Issue #18101: Tcl.split() now process Unicode strings nested in a tuple as it do with byte strings. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 21:22:36 2013 From: python-checkins at python.org (barry.warsaw) Date: Mon, 15 Jul 2013 21:22:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogLSBJc3N1ZSAjMTg0?= =?utf-8?q?40=3A_Clarify_that_=60hash=28=29=60_can_truncate_the_value_retu?= =?utf-8?q?rned_from_an?= Message-ID: <3bvF4X5Qjtz7LkK@mail.python.org> http://hg.python.org/cpython/rev/8fe13940b033 changeset: 84637:8fe13940b033 branch: 3.3 parent: 84632:6a6ca7c49c2a user: Barry Warsaw date: Mon Jul 15 14:47:29 2013 -0400 summary: - Issue #18440: Clarify that `hash()` can truncate the value returned from an object's custom `__hash__()` method. files: Doc/library/functions.rst | 13 +++++++++---- Doc/reference/datamodel.rst | 19 +++++++++++++++---- Misc/NEWS | 3 +++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -583,11 +583,16 @@ .. function:: hash(object) - Return the hash value of the object (if it has one). Hash values are integers. - They are used to quickly compare dictionary keys during a dictionary lookup. - Numeric values that compare equal have the same hash value (even if they are of - different types, as is the case for 1 and 1.0). + Return the hash value of the object (if it has one). Hash values are + integers. They are used to quickly compare dictionary keys during a + dictionary lookup. Numeric values that compare equal have the same hash + value (even if they are of different types, as is the case for 1 and 1.0). + .. note:: + + For object's with custom :meth:`__hash__` methods, note that :func:`hash` + truncates the return value based on the bit width of the host machine. + See :meth:`__hash__` for details. .. function:: help([object]) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1264,10 +1264,21 @@ Called by built-in function :func:`hash` and for operations on members of hashed collections including :class:`set`, :class:`frozenset`, and - :class:`dict`. :meth:`__hash__` should return an integer. The only required - property is that objects which compare equal have the same hash value; it is - advised to somehow mix together (e.g. using exclusive or) the hash values for - the components of the object that also play a part in comparison of objects. + :class:`dict`. :meth:`__hash__` should return an integer. The only + required property is that objects which compare equal have the same hash + value; it is advised to somehow mix together (e.g. using exclusive or) the + hash values for the components of the object that also play a part in + comparison of objects. + + .. note:: + + :func:`hash` truncates the value returned from an object's custom + :meth:`__hash__` method to the size of a :c:type:`Py_ssize_t`. This is + typically 8 bytes on 64-bit builds and 4 bytes on 32-bit builds. If an + object's :meth:`__hash__` must interoperate on builds of different bit + sizes, be sure to check the width on all supported builds. An easy way + to do this is with + ``python -c "import sys; print(sys.hash_info.width)"`` If a class does not define an :meth:`__eq__` method it should not define a :meth:`__hash__` operation either; if it defines :meth:`__eq__` but not diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -210,6 +210,9 @@ Documentation ------------- +- Issue #18440: Clarify that `hash()` can truncate the value returned from an + object's custom `__hash__()` method. + - Issue #17953: Mention that you shouldn't replace sys.modules and deleting key items will cause Python to not be happy. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 15 21:22:38 2013 From: python-checkins at python.org (barry.warsaw) Date: Mon, 15 Jul 2013 21:22:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_-_Issue_=2318440=3A_Clarify_that_=60hash=28=29=60_can_tr?= =?utf-8?q?uncate_the_value_returned_from_an?= Message-ID: <3bvF4Z0Nqlz7LkD@mail.python.org> http://hg.python.org/cpython/rev/f01f0c9cbcc8 changeset: 84638:f01f0c9cbcc8 parent: 84634:ccbaf6762b54 parent: 84637:8fe13940b033 user: Barry Warsaw date: Mon Jul 15 15:21:41 2013 -0400 summary: - Issue #18440: Clarify that `hash()` can truncate the value returned from an object's custom `__hash__()` method. files: Doc/library/functions.rst | 13 +++++++++---- Doc/reference/datamodel.rst | 19 +++++++++++++++---- Misc/NEWS | 3 +++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -587,11 +587,16 @@ .. function:: hash(object) - Return the hash value of the object (if it has one). Hash values are integers. - They are used to quickly compare dictionary keys during a dictionary lookup. - Numeric values that compare equal have the same hash value (even if they are of - different types, as is the case for 1 and 1.0). + Return the hash value of the object (if it has one). Hash values are + integers. They are used to quickly compare dictionary keys during a + dictionary lookup. Numeric values that compare equal have the same hash + value (even if they are of different types, as is the case for 1 and 1.0). + .. note:: + + For object's with custom :meth:`__hash__` methods, note that :func:`hash` + truncates the return value based on the bit width of the host machine. + See :meth:`__hash__` for details. .. function:: help([object]) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1264,10 +1264,21 @@ Called by built-in function :func:`hash` and for operations on members of hashed collections including :class:`set`, :class:`frozenset`, and - :class:`dict`. :meth:`__hash__` should return an integer. The only required - property is that objects which compare equal have the same hash value; it is - advised to somehow mix together (e.g. using exclusive or) the hash values for - the components of the object that also play a part in comparison of objects. + :class:`dict`. :meth:`__hash__` should return an integer. The only + required property is that objects which compare equal have the same hash + value; it is advised to somehow mix together (e.g. using exclusive or) the + hash values for the components of the object that also play a part in + comparison of objects. + + .. note:: + + :func:`hash` truncates the value returned from an object's custom + :meth:`__hash__` method to the size of a :c:type:`Py_ssize_t`. This is + typically 8 bytes on 64-bit builds and 4 bytes on 32-bit builds. If an + object's :meth:`__hash__` must interoperate on builds of different bit + sizes, be sure to check the width on all supported builds. An easy way + to do this is with + ``python -c "import sys; print(sys.hash_info.width)"`` If a class does not define an :meth:`__eq__` method it should not define a :meth:`__hash__` operation either; if it defines :meth:`__eq__` but not diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -581,6 +581,9 @@ Documentation ------------- +- Issue #18440: Clarify that `hash()` can truncate the value returned from an + object's custom `__hash__()` method. + - 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 Tue Jul 16 00:12:46 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 00:12:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_pyex?= =?utf-8?q?pat=2EParserCreate=28=29?= Message-ID: <3bvJrt3gv9z7Llt@mail.python.org> http://hg.python.org/cpython/rev/735e3c43e61c changeset: 84639:735e3c43e61c user: Victor Stinner date: Mon Jul 15 17:15:57 2013 +0200 summary: Issue #18408: Fix pyexpat.ParserCreate() Check if XML_ParserCreate_MM() failed (ex: MemoryError) before using self->itself. files: Modules/pyexpat.c | 19 ++++++++++--------- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1180,9 +1180,19 @@ self->in_callback = 0; self->ns_prefixes = 0; self->handlers = NULL; + self->intern = intern; + Py_XINCREF(self->intern); + PyObject_GC_Track(self); + /* namespace_separator is either NULL or contains one char + \0 */ self->itself = XML_ParserCreate_MM(encoding, &ExpatMemoryHandler, namespace_separator); + if (self->itself == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "XML_ParserCreate failed"); + Py_DECREF(self); + return NULL; + } #if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) /* This feature was added upstream in libexpat 2.1.0. Our expat copy * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT @@ -1190,15 +1200,6 @@ XML_SetHashSalt(self->itself, (unsigned long)_Py_HashSecret.prefix); #endif - self->intern = intern; - Py_XINCREF(self->intern); - PyObject_GC_Track(self); - if (self->itself == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "XML_ParserCreate failed"); - Py_DECREF(self); - return NULL; - } XML_SetUserData(self->itself, (void *)self); XML_SetUnknownEncodingHandler(self->itself, (XML_UnknownEncodingHandler) PyUnknownEncodingHandler, NULL); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 00:12:47 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 00:12:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_CJK_?= =?utf-8?q?decoders=2C_raise_MemoryError_on_memory_allocation_failure?= Message-ID: <3bvJrv5XLqz7Ll1@mail.python.org> http://hg.python.org/cpython/rev/27f8ccce687d changeset: 84640:27f8ccce687d user: Victor Stinner date: Mon Jul 15 17:47:39 2013 +0200 summary: Issue #18408: Fix CJK decoders, raise MemoryError on memory allocation failure files: Modules/cjkcodecs/multibytecodec.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -1053,8 +1053,10 @@ } wsize = size + self->pendingsize; wdata = PyMem_Malloc(wsize); - if (wdata == NULL) + if (wdata == NULL) { + PyErr_NoMemory(); goto errorexit; + } memcpy(wdata, self->pending, self->pendingsize); memcpy(wdata + self->pendingsize, data, size); self->pendingsize = 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 00:12:49 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 00:12:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_PyObject?= =?utf-8?q?=5FCall=28=29_now_fails_with_an_assertion_error_in_debug_mode?= Message-ID: <3bvJrx0CMkz7LkD@mail.python.org> http://hg.python.org/cpython/rev/82b2ee140994 changeset: 84641:82b2ee140994 user: Victor Stinner date: Mon Jul 15 17:50:07 2013 +0200 summary: Issue #18408: PyObject_Call() now fails with an assertion error in debug mode if the function called failed whereas no exception was raised, to detect bugs earlier. files: Objects/abstract.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2104,10 +2104,16 @@ return NULL; result = (*call)(func, arg, kw); Py_LeaveRecursiveCall(); - if (result == NULL && !PyErr_Occurred()) +#ifdef NDEBUG + if (result == NULL && !PyErr_Occurred()) { PyErr_SetString( PyExc_SystemError, "NULL result without error in PyObject_Call"); + } +#else + if (result == NULL) + assert(PyErr_Occurred()); +#endif return result; } PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 00:12:50 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 00:12:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Don=27t_?= =?utf-8?q?check_unicode_consistency_in_=5FPyUnicode=5FHAS=5FUTF8=5FMEMORY?= =?utf-8?b?KCk=?= Message-ID: <3bvJry2MpWz7Lkx@mail.python.org> http://hg.python.org/cpython/rev/ef0dbe00760e changeset: 84642:ef0dbe00760e user: Victor Stinner date: Mon Jul 15 18:22:47 2013 +0200 summary: Issue #18408: Don't check unicode consistency in _PyUnicode_HAS_UTF8_MEMORY() and _PyUnicode_HAS_WSTR_MEMORY() macros These macros are called in unicode_dealloc(), whereas the unicode object can be "inconsistent" if the creation of the object failed. For example, when unicode_subtype_new() fails on a memory allocation, _PyUnicode_CheckConsistency() fails with an assertion error because data is NULL. files: Objects/unicodeobject.c | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -122,16 +122,14 @@ /* true if the Unicode object has an allocated UTF-8 memory block (not shared with other data) */ #define _PyUnicode_HAS_UTF8_MEMORY(op) \ - (assert(_PyUnicode_CHECK(op)), \ - (!PyUnicode_IS_COMPACT_ASCII(op) \ + ((!PyUnicode_IS_COMPACT_ASCII(op) \ && _PyUnicode_UTF8(op) \ && _PyUnicode_UTF8(op) != PyUnicode_DATA(op))) /* true if the Unicode object has an allocated wstr memory block (not shared with other data) */ #define _PyUnicode_HAS_WSTR_MEMORY(op) \ - (assert(_PyUnicode_CHECK(op)), \ - (_PyUnicode_WSTR(op) && \ + ((_PyUnicode_WSTR(op) && \ (!PyUnicode_IS_READY(op) || \ _PyUnicode_WSTR(op) != PyUnicode_DATA(op)))) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 00:12:51 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 00:12:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_type=5Fn?= =?utf-8?q?ew=28=29_and_PyType=5FFromSpecWithBases=28=29_now_raise_MemoryE?= =?utf-8?q?rror?= Message-ID: <3bvJrz4H0Pz7LkV@mail.python.org> http://hg.python.org/cpython/rev/c676fc74d779 changeset: 84643:c676fc74d779 user: Victor Stinner date: Mon Jul 15 19:34:20 2013 +0200 summary: Issue #18408: type_new() and PyType_FromSpecWithBases() now raise MemoryError on memory allocation failure files: Objects/typeobject.c | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2292,8 +2292,10 @@ /* Silently truncate the docstring if it contains null bytes. */ len = strlen(doc_str); tp_doc = (char *)PyObject_MALLOC(len + 1); - if (tp_doc == NULL) + if (tp_doc == NULL) { + PyErr_NoMemory(); goto error; + } memcpy(tp_doc, doc_str, len + 1); type->tp_doc = tp_doc; } @@ -2496,8 +2498,10 @@ if (slot->slot == Py_tp_doc) { size_t len = strlen(slot->pfunc)+1; char *tp_doc = PyObject_MALLOC(len); - if (tp_doc == NULL) + if (tp_doc == NULL) { + PyErr_NoMemory(); goto fail; + } memcpy(tp_doc, slot->pfunc, len); type->tp_doc = tp_doc; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 00:12:52 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 00:12:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_test=5Fio=3A_check=5Finter?= =?utf-8?q?rupted=5Fwrite=28=29_now_cancels_the_alarm_if_ZeroDivisionError?= Message-ID: <3bvJs0671gz7Lkl@mail.python.org> http://hg.python.org/cpython/rev/638f9cfa7b0a changeset: 84644:638f9cfa7b0a user: Victor Stinner date: Mon Jul 15 19:53:13 2013 +0200 summary: test_io: check_interrupted_write() now cancels the alarm if ZeroDivisionError exception was not raised. Before the process was killed by SIGALRM in another random test (1 second later) files: Lib/test/test_io.py | 9 ++++++--- 1 files changed, 6 insertions(+), 3 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 @@ -3070,15 +3070,18 @@ try: wio = self.io.open(w, **fdopen_kwargs) t.start() - signal.alarm(1) # Fill the pipe enough that the write will be blocking. # It will be interrupted by the timer armed above. Since the # other thread has read one byte, the low-level write will # return with a successful (partial) result rather than an EINTR. # The buffered IO layer must check for pending signal # handlers, which in this case will invoke alarm_interrupt(). - self.assertRaises(ZeroDivisionError, - wio.write, item * (support.PIPE_MAX_SIZE // len(item) + 1)) + signal.alarm(1) + try: + self.assertRaises(ZeroDivisionError, + wio.write, item * (support.PIPE_MAX_SIZE // len(item) + 1)) + finally: + signal.alarm(0) t.join() # We got one byte, get another one and check that it isn't a # repeat of the first one. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 00:12:54 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 00:12:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_random?= =?utf-8?q?=5Fseed=28=29_now_raises_a_MemoryError_on_memory_allocation?= Message-ID: <3bvJs20vLSz7LlG@mail.python.org> http://hg.python.org/cpython/rev/9244e79c6e14 changeset: 84645:9244e79c6e14 user: Victor Stinner date: Mon Jul 15 20:00:36 2013 +0200 summary: Issue #18408: random_seed() now raises a MemoryError on memory allocation failure files: Modules/_randommodule.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -250,8 +250,10 @@ /* Convert seed to byte sequence. */ key_as_bytes = (unsigned char *)PyMem_Malloc((size_t)4 * keyused); - if (key_as_bytes == NULL) + if (key_as_bytes == NULL) { + PyErr_NoMemory(); goto Done; + } res = _PyLong_AsByteArray((PyLongObject *)n, key_as_bytes, keyused * 4, 1, /* little-endian */ @@ -264,6 +266,7 @@ /* Fill array of unsigned longs from byte sequence. */ key = (unsigned long *)PyMem_Malloc(sizeof(unsigned long) * keyused); if (key == NULL) { + PyErr_NoMemory(); PyMem_Free(key_as_bytes); goto Done; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 00:12:55 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 00:12:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_PyEv?= =?utf-8?q?al=5FEvalFrameEx=28=29_for_MemoryError?= Message-ID: <3bvJs32sBMz7Lkl@mail.python.org> http://hg.python.org/cpython/rev/71a572a516f9 changeset: 84646:71a572a516f9 user: Victor Stinner date: Mon Jul 15 21:16:27 2013 +0200 summary: Issue #18408: Fix PyEval_EvalFrameEx() for MemoryError Don't pass a NULL traceback to PyException_SetTraceback(): pass Py_None. Passing NULL would raise a new exception. files: Python/ceval.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3090,7 +3090,10 @@ Python main loop. */ PyErr_NormalizeException( &exc, &val, &tb); - PyException_SetTraceback(val, tb); + if (tb != NULL) + PyException_SetTraceback(val, tb); + else + PyException_SetTraceback(val, Py_None); Py_INCREF(exc); tstate->exc_type = exc; Py_INCREF(val); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 02:02:13 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 02:02:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_=5FP?= =?utf-8?q?y=5FDisplaySourceLine=28=29?= Message-ID: <3bvMH92Yv7z7LjT@mail.python.org> http://hg.python.org/cpython/rev/2e42c0a39321 changeset: 84647:2e42c0a39321 user: Victor Stinner date: Tue Jul 16 00:32:14 2013 +0200 summary: Issue #18408: Fix _Py_DisplaySourceLine() Report _Py_FindSourceFile() error, so the error is cleared; and clear io.open(filename) exception on failure. files: Python/traceback.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -246,10 +246,12 @@ binary = _PyObject_CallMethodId(io, &PyId_open, "Os", filename, "rb"); if (binary == NULL) { + PyErr_Clear(); + binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io); if (binary == NULL) { Py_DECREF(io); - return 0; + return -1; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 02:02:14 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 02:02:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_add_more?= =?utf-8?q?_assertions_on_PyErr=5FOccurred=28=29_in_ceval=2Ec_to_detect_bu?= =?utf-8?q?gs?= Message-ID: <3bvMHB4WVQz7Lkc@mail.python.org> http://hg.python.org/cpython/rev/92a9ccb2a521 changeset: 84648:92a9ccb2a521 user: Victor Stinner date: Tue Jul 16 01:02:12 2013 +0200 summary: Issue #18408: add more assertions on PyErr_Occurred() in ceval.c to detect bugs earlier files: Objects/abstract.c | 3 +-- Python/ceval.c | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2111,8 +2111,7 @@ "NULL result without error in PyObject_Call"); } #else - if (result == NULL) - assert(PyErr_Occurred()); + assert(result != NULL || PyErr_Occurred()); #endif return result; } diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4216,6 +4216,8 @@ READ_TIMESTAMP(*pintr1); Py_DECREF(func); } + assert((x != NULL && !PyErr_Occurred()) + || (x == NULL && PyErr_Occurred())); /* Clear the stack of the function object. Also removes the arguments in case they weren't consumed already @@ -4509,6 +4511,8 @@ Py_XDECREF(callargs); Py_XDECREF(kwdict); Py_XDECREF(stararg); + assert((result != NULL && !PyErr_Occurred()) + || (result == NULL && PyErr_Occurred())); return result; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 02:02:15 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 02:02:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_show?= =?utf-8?q?=5Fwarning=28=29=2C_clear_also_the_exception_raised_by?= Message-ID: <3bvMHC6M8kz7Lkc@mail.python.org> http://hg.python.org/cpython/rev/9213313b1a6f changeset: 84649:9213313b1a6f user: Victor Stinner date: Tue Jul 16 01:54:37 2013 +0200 summary: Issue #18408: Fix show_warning(), clear also the exception raised by _Py_DisplaySourceLine() For example, _PyGC_DumpShutdownStats() calls PyErr_WarnExplicitFormat() while the import machinery does not work anymore, _Py_DisplaySourceLine() fails when trying to import the io module. files: Python/_warnings.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -283,9 +283,9 @@ PyFile_WriteString(source_line_str, f_stderr); PyFile_WriteString("\n", f_stderr); } - else - if (_Py_DisplaySourceLine(f_stderr, filename, lineno, 2) < 0) - return; + else { + _Py_DisplaySourceLine(f_stderr, filename, lineno, 2); + } PyErr_Clear(); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 04:09:55 2013 From: python-checkins at python.org (ned.deily) Date: Tue, 16 Jul 2013 04:09:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDcx?= =?utf-8?q?=3A_Fix_typo_in_heapq_documentation_=28reported_by_Fran=C3=A7oi?= =?utf-8?q?s_Pinard=29=2E?= Message-ID: <3bvQ6W39dYz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/236e6b995300 changeset: 84650:236e6b995300 branch: 2.7 parent: 84636:542a317d4351 user: Ned Deily date: Mon Jul 15 19:07:41 2013 -0700 summary: Issue #18471: Fix typo in heapq documentation (reported by Fran?ois Pinard). files: Doc/library/heapq.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/heapq.rst b/Doc/library/heapq.rst --- a/Doc/library/heapq.rst +++ b/Doc/library/heapq.rst @@ -260,7 +260,7 @@ the sort is going on, provided that the inserted items are not "better" than the last 0'th element you extracted. This is especially useful in simulation contexts, where the tree holds all incoming events, and the "win" condition -means the smallest scheduled time. When an event schedule other events for +means the smallest scheduled time. When an event schedules other events for execution, they are scheduled into the future, so they can easily go into the heap. So, a heap is a good structure for implementing schedulers (this is what I used for my MIDI sequencer :-). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 04:09:56 2013 From: python-checkins at python.org (ned.deily) Date: Tue, 16 Jul 2013 04:09:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDcx?= =?utf-8?q?=3A_Fix_typo_in_heapq_documentation_=28reported_by_Fran=C3=A7oi?= =?utf-8?q?s_Pinard=29=2E?= Message-ID: <3bvQ6X51q2z7Ll1@mail.python.org> http://hg.python.org/cpython/rev/e22dd5fda5a8 changeset: 84651:e22dd5fda5a8 branch: 3.3 parent: 84637:8fe13940b033 user: Ned Deily date: Mon Jul 15 19:08:13 2013 -0700 summary: Issue #18471: Fix typo in heapq documentation (reported by Fran?ois Pinard). files: Doc/library/heapq.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/heapq.rst b/Doc/library/heapq.rst --- a/Doc/library/heapq.rst +++ b/Doc/library/heapq.rst @@ -246,7 +246,7 @@ the sort is going on, provided that the inserted items are not "better" than the last 0'th element you extracted. This is especially useful in simulation contexts, where the tree holds all incoming events, and the "win" condition -means the smallest scheduled time. When an event schedule other events for +means the smallest scheduled time. When an event schedules other events for execution, they are scheduled into the future, so they can easily go into the heap. So, a heap is a good structure for implementing schedulers (this is what I used for my MIDI sequencer :-). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 04:09:57 2013 From: python-checkins at python.org (ned.deily) Date: Tue, 16 Jul 2013 04:09:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2318471=3A_Fix_typo_in_heapq_documentation_=28re?= =?utf-8?q?ported_by_Fran=C3=A7ois_Pinard=29=2E?= Message-ID: <3bvQ6Y6rLRz7Ll1@mail.python.org> http://hg.python.org/cpython/rev/8a078bf3cf14 changeset: 84652:8a078bf3cf14 parent: 84649:9213313b1a6f parent: 84651:e22dd5fda5a8 user: Ned Deily date: Mon Jul 15 19:09:27 2013 -0700 summary: Closes #18471: Fix typo in heapq documentation (reported by Fran?ois Pinard). files: Doc/library/heapq.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/heapq.rst b/Doc/library/heapq.rst --- a/Doc/library/heapq.rst +++ b/Doc/library/heapq.rst @@ -246,7 +246,7 @@ the sort is going on, provided that the inserted items are not "better" than the last 0'th element you extracted. This is especially useful in simulation contexts, where the tree holds all incoming events, and the "win" condition -means the smallest scheduled time. When an event schedule other events for +means the smallest scheduled time. When an event schedules other events for execution, they are scheduled into the future, so they can easily go into the heap. So, a heap is a good structure for implementing schedulers (this is what I used for my MIDI sequencer :-). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 04:17:28 2013 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 16 Jul 2013 04:17:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_check_the_retu?= =?utf-8?q?rn_value_of_new=5Fstring=28=29_=28closes_=2318470=29?= Message-ID: <3bvQHD4yjMz7LlT@mail.python.org> http://hg.python.org/cpython/rev/c3a510b22218 changeset: 84653:c3a510b22218 branch: 3.3 parent: 84651:e22dd5fda5a8 user: Benjamin Peterson date: Mon Jul 15 19:15:34 2013 -0700 summary: check the return value of new_string() (closes #18470) files: Parser/tokenizer.c | 82 +++++++++++++++++++-------------- 1 files changed, 46 insertions(+), 36 deletions(-) diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -147,13 +147,15 @@ } static char * -new_string(const char *s, Py_ssize_t len) +new_string(const char *s, Py_ssize_t len, struct tok_state *tok) { char* result = (char *)PyMem_MALLOC(len + 1); - if (result != NULL) { - memcpy(result, s, len); - result[len] = '\0'; + if (!result) { + tok->done = E_NOMEM; + return NULL; } + memcpy(result, s, len); + result[len] = '\0'; return result; } @@ -174,7 +176,7 @@ static char * decode_str(const char *str, int exec_input, struct tok_state *tok) { - return new_string(str, strlen(str)); + return new_string(str, strlen(str), tok); } #else /* PGEN */ @@ -221,17 +223,18 @@ /* Return the coding spec in S, or NULL if none is found. */ -static char * -get_coding_spec(const char *s, Py_ssize_t size) +static int +get_coding_spec(const char *s, char **spec, Py_ssize_t size, struct tok_state *tok) { Py_ssize_t i; + *spec = NULL; /* Coding spec must be in a comment, and that comment must be * the only statement on the source code line. */ for (i = 0; i < size - 6; i++) { if (s[i] == '#') break; if (s[i] != ' ' && s[i] != '\t' && s[i] != '\014') - return NULL; + return 1; } for (; i < size - 6; i++) { /* XXX inefficient search */ const char* t = s + i; @@ -250,17 +253,21 @@ t++; if (begin < t) { - char* r = new_string(begin, t - begin); + char* r = new_string(begin, t - begin, tok); + if (!r) + return 0; char* q = get_normal_name(r); if (r != q) { PyMem_FREE(r); - r = new_string(q, strlen(q)); + r = new_string(q, strlen(q), tok); + if (!r) + return 0; } - return r; + *spec = r; } } } - return NULL; + return 1; } /* Check whether the line contains a coding spec. If it does, @@ -272,38 +279,39 @@ check_coding_spec(const char* line, Py_ssize_t size, struct tok_state *tok, int set_readline(struct tok_state *, const char *)) { - char * cs; + char *cs; int r = 1; if (tok->cont_line) /* It's a continuation line, so it can't be a coding spec. */ return 1; - cs = get_coding_spec(line, size); - if (cs != NULL) { - tok->read_coding_spec = 1; - if (tok->encoding == NULL) { - assert(tok->decoding_state == STATE_RAW); - if (strcmp(cs, "utf-8") == 0) { + if (!get_coding_spec(line, &cs, size, tok)) + return 0; + if (!cs) + return 1; + tok->read_coding_spec = 1; + if (tok->encoding == NULL) { + assert(tok->decoding_state == STATE_RAW); + if (strcmp(cs, "utf-8") == 0) { + tok->encoding = cs; + } else { + r = set_readline(tok, cs); + if (r) { tok->encoding = cs; - } else { - r = set_readline(tok, cs); - if (r) { - tok->encoding = cs; - tok->decoding_state = STATE_NORMAL; - } - else { - PyErr_Format(PyExc_SyntaxError, - "encoding problem: %s", cs); - PyMem_FREE(cs); - } + tok->decoding_state = STATE_NORMAL; } - } else { /* then, compare cs with BOM */ - r = (strcmp(tok->encoding, cs) == 0); - if (!r) + else { PyErr_Format(PyExc_SyntaxError, - "encoding problem: %s with BOM", cs); - PyMem_FREE(cs); + "encoding problem: %s", cs); + PyMem_FREE(cs); + } } + } else { /* then, compare cs with BOM */ + r = (strcmp(tok->encoding, cs) == 0); + if (!r) + PyErr_Format(PyExc_SyntaxError, + "encoding problem: %s with BOM", cs); + PyMem_FREE(cs); } return r; } @@ -367,7 +375,9 @@ } if (tok->encoding != NULL) PyMem_FREE(tok->encoding); - tok->encoding = new_string("utf-8", 5); /* resulting is in utf-8 */ + tok->encoding = new_string("utf-8", 5, tok); + if (!tok->encoding) + return 0; /* No need to set_readline: input is already utf-8 */ return 1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 04:17:29 2013 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 16 Jul 2013 04:17:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_3=2E3?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMTg0NzAp?= Message-ID: <3bvQHF6dScz7Lp9@mail.python.org> http://hg.python.org/cpython/rev/8889c9b5dd3a changeset: 84654:8889c9b5dd3a branch: 3.3 parent: 84653:c3a510b22218 parent: 84652:8a078bf3cf14 user: Benjamin Peterson date: Mon Jul 15 19:15:49 2013 -0700 summary: merge 3.3 (#18470) files: -- Repository URL: http://hg.python.org/cpython From root at python.org Tue Jul 16 05:45:02 2013 From: root at python.org (Cron Daemon) Date: Tue, 16 Jul 2013 05:45:02 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: HTTP Error 500: Internal Server Error From python-checkins at python.org Tue Jul 16 05:47:55 2013 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 16 Jul 2013 05:47:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_3=2E3_=28closes_=2318470=29?= Message-ID: <3bvSHb0y2Bz7LjT@mail.python.org> http://hg.python.org/cpython/rev/2650127ce034 changeset: 84654:2650127ce034 parent: 84652:8a078bf3cf14 parent: 84653:c3a510b22218 user: Benjamin Peterson date: Mon Jul 15 20:47:47 2013 -0700 summary: merge 3.3 (closes #18470) files: Parser/tokenizer.c | 82 +++++++++++++++++++-------------- 1 files changed, 46 insertions(+), 36 deletions(-) diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -147,13 +147,15 @@ } static char * -new_string(const char *s, Py_ssize_t len) +new_string(const char *s, Py_ssize_t len, struct tok_state *tok) { char* result = (char *)PyMem_MALLOC(len + 1); - if (result != NULL) { - memcpy(result, s, len); - result[len] = '\0'; + if (!result) { + tok->done = E_NOMEM; + return NULL; } + memcpy(result, s, len); + result[len] = '\0'; return result; } @@ -174,7 +176,7 @@ static char * decode_str(const char *str, int exec_input, struct tok_state *tok) { - return new_string(str, strlen(str)); + return new_string(str, strlen(str), tok); } #else /* PGEN */ @@ -221,17 +223,18 @@ /* Return the coding spec in S, or NULL if none is found. */ -static char * -get_coding_spec(const char *s, Py_ssize_t size) +static int +get_coding_spec(const char *s, char **spec, Py_ssize_t size, struct tok_state *tok) { Py_ssize_t i; + *spec = NULL; /* Coding spec must be in a comment, and that comment must be * the only statement on the source code line. */ for (i = 0; i < size - 6; i++) { if (s[i] == '#') break; if (s[i] != ' ' && s[i] != '\t' && s[i] != '\014') - return NULL; + return 1; } for (; i < size - 6; i++) { /* XXX inefficient search */ const char* t = s + i; @@ -250,17 +253,21 @@ t++; if (begin < t) { - char* r = new_string(begin, t - begin); + char* r = new_string(begin, t - begin, tok); + if (!r) + return 0; char* q = get_normal_name(r); if (r != q) { PyMem_FREE(r); - r = new_string(q, strlen(q)); + r = new_string(q, strlen(q), tok); + if (!r) + return 0; } - return r; + *spec = r; } } } - return NULL; + return 1; } /* Check whether the line contains a coding spec. If it does, @@ -272,38 +279,39 @@ check_coding_spec(const char* line, Py_ssize_t size, struct tok_state *tok, int set_readline(struct tok_state *, const char *)) { - char * cs; + char *cs; int r = 1; if (tok->cont_line) /* It's a continuation line, so it can't be a coding spec. */ return 1; - cs = get_coding_spec(line, size); - if (cs != NULL) { - tok->read_coding_spec = 1; - if (tok->encoding == NULL) { - assert(tok->decoding_state == STATE_RAW); - if (strcmp(cs, "utf-8") == 0) { + if (!get_coding_spec(line, &cs, size, tok)) + return 0; + if (!cs) + return 1; + tok->read_coding_spec = 1; + if (tok->encoding == NULL) { + assert(tok->decoding_state == STATE_RAW); + if (strcmp(cs, "utf-8") == 0) { + tok->encoding = cs; + } else { + r = set_readline(tok, cs); + if (r) { tok->encoding = cs; - } else { - r = set_readline(tok, cs); - if (r) { - tok->encoding = cs; - tok->decoding_state = STATE_NORMAL; - } - else { - PyErr_Format(PyExc_SyntaxError, - "encoding problem: %s", cs); - PyMem_FREE(cs); - } + tok->decoding_state = STATE_NORMAL; } - } else { /* then, compare cs with BOM */ - r = (strcmp(tok->encoding, cs) == 0); - if (!r) + else { PyErr_Format(PyExc_SyntaxError, - "encoding problem: %s with BOM", cs); - PyMem_FREE(cs); + "encoding problem: %s", cs); + PyMem_FREE(cs); + } } + } else { /* then, compare cs with BOM */ + r = (strcmp(tok->encoding, cs) == 0); + if (!r) + PyErr_Format(PyExc_SyntaxError, + "encoding problem: %s with BOM", cs); + PyMem_FREE(cs); } return r; } @@ -367,7 +375,9 @@ } if (tok->encoding != NULL) PyMem_FREE(tok->encoding); - tok->encoding = new_string("utf-8", 5); /* resulting is in utf-8 */ + tok->encoding = new_string("utf-8", 5, tok); + if (!tok->encoding) + return 0; /* No need to set_readline: input is already utf-8 */ return 1; } -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jul 16 05:48:30 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 16 Jul 2013 05:48:30 +0200 Subject: [Python-checkins] Daily reference leaks (9213313b1a6f): sum=0 Message-ID: results for 9213313b1a6f on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogt6OINy', '-x'] From python-checkins at python.org Tue Jul 16 05:50:32 2013 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 16 Jul 2013 05:50:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_move_declarati?= =?utf-8?q?on_to_top_of_block?= Message-ID: <3bvSLc5vYHz7Ljx@mail.python.org> http://hg.python.org/cpython/rev/72312ff5f712 changeset: 84655:72312ff5f712 branch: 3.3 parent: 84653:c3a510b22218 user: Benjamin Peterson date: Mon Jul 15 20:50:22 2013 -0700 summary: move declaration to top of block files: Parser/tokenizer.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -254,9 +254,10 @@ if (begin < t) { char* r = new_string(begin, t - begin, tok); + char* q; if (!r) return 0; - char* q = get_normal_name(r); + q = get_normal_name(r); if (r != q) { PyMem_FREE(r); r = new_string(q, strlen(q), tok); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 05:50:34 2013 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 16 Jul 2013 05:50:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3bvSLf0cbvz7Llx@mail.python.org> http://hg.python.org/cpython/rev/daf9ea42b610 changeset: 84656:daf9ea42b610 parent: 84654:2650127ce034 parent: 84655:72312ff5f712 user: Benjamin Peterson date: Mon Jul 15 20:50:25 2013 -0700 summary: merge 3.3 files: Parser/tokenizer.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -254,9 +254,10 @@ if (begin < t) { char* r = new_string(begin, t - begin, tok); + char* q; if (!r) return 0; - char* q = get_normal_name(r); + q = get_normal_name(r); if (r != q) { PyMem_FREE(r); r = new_string(q, strlen(q), tok); -- Repository URL: http://hg.python.org/cpython From benjamin at python.org Tue Jul 16 05:55:16 2013 From: benjamin at python.org (Benjamin Peterson) Date: Mon, 15 Jul 2013 20:55:16 -0700 Subject: [Python-checkins] [Python-Dev] cpython (3.3): check the return value of new_string() (closes #18470) In-Reply-To: References: <3bvQHD4yjMz7LlT@mail.python.org> Message-ID: 2013/7/15 Victor Stinner : > 2013/7/16 benjamin.peterson : >> http://hg.python.org/cpython/rev/c3a510b22218 >> changeset: 84653:c3a510b22218 >> branch: 3.3 >> parent: 84651:e22dd5fda5a8 >> user: Benjamin Peterson >> date: Mon Jul 15 19:15:34 2013 -0700 >> summary: >> check the return value of new_string() (closes #18470) >> >> ... >> >> >> diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c >> --- a/Parser/tokenizer.c >> +++ b/Parser/tokenizer.c >> @@ -250,17 +253,21 @@ >> t++; >> >> if (begin < t) { >> - char* r = new_string(begin, t - begin); >> + char* r = new_string(begin, t - begin, tok); >> + if (!r) >> + return 0; >> char* q = get_normal_name(r); >> ... > > Visual Studio does support instructions between declarations, and so > this changeset broke Windows buildbots. Fixed. > > Should we add the "-Werror=declaration-after-statement" compiler flag > to the 3.3 branch? (in debug mode?) We've lived with this limitation for years. I'm sure we can wait until 3.4 becomes maintenance. :) -- Regards, Benjamin From python-checkins at python.org Tue Jul 16 08:32:32 2013 From: python-checkins at python.org (ronald.oussoren) Date: Tue, 16 Jul 2013 08:32:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Also_remove_a_=28broken=29?= =?utf-8?q?_leaker_test_for_the_code_removed_in_issue_=2318393=2E?= Message-ID: <3bvWxX39G9z7LjN@mail.python.org> http://hg.python.org/cpython/rev/7272ef213b7c changeset: 84657:7272ef213b7c user: Ronald Oussoren date: Tue Jul 16 08:32:05 2013 +0200 summary: Also remove a (broken) leaker test for the code removed in issue #18393. files: Lib/test/leakers/test_gestalt.py | 14 -------------- 1 files changed, 0 insertions(+), 14 deletions(-) diff --git a/Lib/test/leakers/test_gestalt.py b/Lib/test/leakers/test_gestalt.py deleted file mode 100644 --- a/Lib/test/leakers/test_gestalt.py +++ /dev/null @@ -1,14 +0,0 @@ -import sys - -if sys.platform != 'darwin': - raise ValueError("This test only leaks on Mac OS X") - -def leak(): - # taken from platform._mac_ver_lookup() - from gestalt import gestalt - import MacOS - - try: - gestalt('sysu') - except MacOS.Error: - pass -- Repository URL: http://hg.python.org/cpython From ronaldoussoren at mac.com Tue Jul 16 08:32:41 2013 From: ronaldoussoren at mac.com (Ronald Oussoren) Date: Tue, 16 Jul 2013 08:32:41 +0200 Subject: [Python-checkins] [Python-Dev] cpython: Issue #18393: Remove use of deprecated API on OSX In-Reply-To: References: <3bv9J80Cjxz7LjQ@mail.python.org> Message-ID: On 15 Jul, 2013, at 18:43, Zachary Ware wrote: > On Mon, Jul 15, 2013 at 11:32 AM, ronald.oussoren > wrote: >> http://hg.python.org/cpython/rev/ccbaf6762b54 >> changeset: 84634:ccbaf6762b54 >> user: Ronald Oussoren >> date: Mon Jul 15 18:32:09 2013 +0200 >> summary: >> Issue #18393: Remove use of deprecated API on OSX >> >> The "Gestalt" function on OSX is deprecated (starting with OSX 10.8), >> remove its usage from the stdlib. The patch removes a number of private > > I believe this means that Lib/test/leakers/test_gestalt.py can be > removed as well. Interesting... test_gestalt.py cannot have worked in Py3k at all. I've removed the file. Thanks, Ronald From victor.stinner at gmail.com Tue Jul 16 04:38:23 2013 From: victor.stinner at gmail.com (Victor Stinner) Date: Tue, 16 Jul 2013 04:38:23 +0200 Subject: [Python-checkins] cpython (merge default -> 3.3): merge 3.3 (#18470) In-Reply-To: <3bvQHF6dScz7Lp9@mail.python.org> References: <3bvQHF6dScz7Lp9@mail.python.org> Message-ID: 2013/7/16 benjamin.peterson : > http://hg.python.org/cpython/rev/8889c9b5dd3a > changeset: 84654:8889c9b5dd3a > branch: 3.3 > parent: 84653:c3a510b22218 > parent: 84652:8a078bf3cf14 > user: Benjamin Peterson > date: Mon Jul 15 19:15:49 2013 -0700 > summary: > merge 3.3 (#18470) This commit merges branches default and 3.3 into 3.3. Usually, we merge branches 3.3 and default into default. Because of this changeset, when I try to merge 3.3 into default, I get a long list of modifications... Victor From victor.stinner at gmail.com Tue Jul 16 04:40:49 2013 From: victor.stinner at gmail.com (Victor Stinner) Date: Tue, 16 Jul 2013 04:40:49 +0200 Subject: [Python-checkins] cpython (3.3): check the return value of new_string() (closes #18470) In-Reply-To: <3bvQHD4yjMz7LlT@mail.python.org> References: <3bvQHD4yjMz7LlT@mail.python.org> Message-ID: 2013/7/16 benjamin.peterson : > http://hg.python.org/cpython/rev/c3a510b22218 > changeset: 84653:c3a510b22218 > branch: 3.3 > parent: 84651:e22dd5fda5a8 > user: Benjamin Peterson > date: Mon Jul 15 19:15:34 2013 -0700 > summary: > check the return value of new_string() (closes #18470) > > ... > > > diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c > --- a/Parser/tokenizer.c > +++ b/Parser/tokenizer.c > @@ -250,17 +253,21 @@ > t++; > > if (begin < t) { > - char* r = new_string(begin, t - begin); > + char* r = new_string(begin, t - begin, tok); > + if (!r) > + return 0; > char* q = get_normal_name(r); > ... Visual Studio does support instructions between declarations, and so this changeset broke Windows buildbots. Should we add the "-Werror=declaration-after-statement" compiler flag to the 3.3 branch? (in debug mode?) Victor From python-checkins at python.org Tue Jul 16 10:59:46 2013 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 16 Jul 2013 10:59:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Move_the_leftl?= =?utf-8?q?ink_to_the_end_of_the_block_structure=2E?= Message-ID: <3bvbCQ2qJ6z7LkH@mail.python.org> http://hg.python.org/cpython/rev/04981ac65138 changeset: 84658:04981ac65138 branch: 2.7 parent: 84650:236e6b995300 user: Raymond Hettinger date: Tue Jul 16 01:59:30 2013 -0700 summary: Move the leftlink to the end of the block structure. The current pattern of memory access will update both the leftlink and rightlink at the same time, so they should be positioned side-by-side for better cache locality. Keeping the leftlink at the front of the structure would make sense only if the paired updates were eliminated by backporting changesets 49a9c734304d, 3555cc0ca35b, ae9ee46bd471, and 744dd749e25b. However, that isn't likely to happen, so we're better off with the leftlink at the end of the structure. files: Modules/_collectionsmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -47,9 +47,9 @@ */ typedef struct BLOCK { - struct BLOCK *leftlink; PyObject *data[BLOCKLEN]; struct BLOCK *rightlink; + struct BLOCK *leftlink; } block; #define MAXFREEBLOCKS 10 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 11:34:28 2013 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 16 Jul 2013 11:34:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backport_c952f?= =?utf-8?q?3d122ae=3A_Tweak_the_deque_struct_by_moving_the_least_used_fiel?= =?utf-8?q?ds?= Message-ID: <3bvbzS0sqcz7Lq3@mail.python.org> http://hg.python.org/cpython/rev/d635e94948a6 changeset: 84659:d635e94948a6 branch: 2.7 user: Raymond Hettinger date: Tue Jul 16 02:34:19 2013 -0700 summary: Backport c952f3d122ae: Tweak the deque struct by moving the least used fields (maxlen and weakref) to the end. files: Modules/_collectionsmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -99,8 +99,8 @@ Py_ssize_t leftindex; /* in range(BLOCKLEN) */ Py_ssize_t rightindex; /* in range(BLOCKLEN) */ Py_ssize_t len; + long state; /* incremented whenever the indices move */ Py_ssize_t maxlen; - long state; /* incremented whenever the indices move */ PyObject *weakreflist; /* List of weak references */ } dequeobject; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 16:58:44 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 16 Jul 2013 16:58:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3Nzc4?= =?utf-8?q?=3A_Fix_test_discovery_for_test=5Fmultiprocessing=2E_=28Patch_b?= =?utf-8?q?y?= Message-ID: <3bvl9c5dq1z7Lk0@mail.python.org> http://hg.python.org/cpython/rev/8a922b28b97d changeset: 84660:8a922b28b97d branch: 3.3 parent: 84655:72312ff5f712 user: Richard Oudkerk date: Tue Jul 16 15:33:41 2013 +0100 summary: Issue #17778: Fix test discovery for test_multiprocessing. (Patch by Zachary Ware.) files: Lib/test/test_multiprocessing.py | 226 ++++++++---------- Misc/NEWS | 3 + 2 files changed, 107 insertions(+), 122 deletions(-) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -19,6 +19,7 @@ import random import logging import struct +import operator import test.support import test.script_helper @@ -1624,6 +1625,18 @@ class _TestPool(BaseTestCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.pool = cls.Pool(4) + + @classmethod + def tearDownClass(cls): + cls.pool.terminate() + cls.pool.join() + cls.pool = None + super().tearDownClass() + def test_apply(self): papply = self.pool.apply self.assertEqual(papply(sqr, (5,)), sqr(5)) @@ -1715,15 +1728,6 @@ p.join() def test_terminate(self): - if self.TYPE == 'manager': - # On Unix a forked process increfs each shared object to - # which its parent process held a reference. If the - # forked process gets terminated then there is likely to - # be a reference leak. So to prevent - # _TestZZZNumberOfObjects from failing we skip this test - # when using a manager. - return - result = self.pool.map_async( time.sleep, [0.1 for i in range(10000)], chunksize=1 ) @@ -1751,7 +1755,6 @@ with multiprocessing.Pool(2) as p: r = p.map_async(sqr, L) self.assertEqual(r.get(), expected) - print(p._state) self.assertRaises(ValueError, p.map_async, sqr, L) def raising(): @@ -1845,35 +1848,6 @@ for (j, res) in enumerate(results): self.assertEqual(res.get(), sqr(j)) - -# -# Test that manager has expected number of shared objects left -# - -class _TestZZZNumberOfObjects(BaseTestCase): - # Because test cases are sorted alphabetically, this one will get - # run after all the other tests for the manager. It tests that - # there have been no "reference leaks" for the manager's shared - # objects. Note the comment in _TestPool.test_terminate(). - - # If some other test using ManagerMixin.manager fails, then the - # raised exception may keep alive a frame which holds a reference - # to a managed object. This will cause test_number_of_objects to - # also fail. - ALLOWED_TYPES = ('manager',) - - def test_number_of_objects(self): - EXPECTED_NUMBER = 1 # the pool object is still alive - multiprocessing.active_children() # discard dead process objs - gc.collect() # do garbage collection - refs = self.manager._number_of_objects() - debug_info = self.manager._debug_info() - if refs != EXPECTED_NUMBER: - print(self.manager._debug_info()) - print(debug_info) - - self.assertEqual(refs, EXPECTED_NUMBER) - # # Test of creating a customized manager class # @@ -2051,7 +2025,7 @@ address=addr, authkey=authkey, serializer=SERIALIZER) try: manager.start() - except IOError as e: + except OSError as e: if e.errno != errno.EADDRINUSE: raise # Retry after some time, in case the old socket was lingering @@ -2165,9 +2139,9 @@ self.assertEqual(reader.writable, False) self.assertEqual(writer.readable, False) self.assertEqual(writer.writable, True) - self.assertRaises(IOError, reader.send, 2) - self.assertRaises(IOError, writer.recv) - self.assertRaises(IOError, writer.poll) + self.assertRaises(OSError, reader.send, 2) + self.assertRaises(OSError, writer.recv) + self.assertRaises(OSError, writer.poll) def test_spawn_close(self): # We test that a pipe connection can be closed by parent @@ -2329,8 +2303,8 @@ if self.TYPE == 'processes': self.assertTrue(a.closed) self.assertTrue(b.closed) - self.assertRaises(IOError, a.recv) - self.assertRaises(IOError, b.recv) + self.assertRaises(OSError, a.recv) + self.assertRaises(OSError, b.recv) class _TestListener(BaseTestCase): @@ -2351,7 +2325,7 @@ self.assertEqual(d.recv(), 1729) if self.TYPE == 'processes': - self.assertRaises(IOError, l.accept) + self.assertRaises(OSError, l.accept) class _TestListenerClient(BaseTestCase): @@ -2401,7 +2375,7 @@ c.close() l.close() -class _TestPoll(unittest.TestCase): +class _TestPoll(BaseTestCase): ALLOWED_TYPES = ('processes', 'threads') @@ -2942,27 +2916,18 @@ def test_invalid_handles(self): conn = multiprocessing.connection.Connection(44977608) try: - self.assertRaises((ValueError, IOError), conn.poll) + self.assertRaises((ValueError, OSError), conn.poll) finally: # Hack private attribute _handle to avoid printing an error # in conn.__del__ conn._handle = None - self.assertRaises((ValueError, IOError), + self.assertRaises((ValueError, OSError), multiprocessing.connection.Connection, -1) # # Functions used to create test cases from the base ones in this module # -def get_attributes(Source, names): - d = {} - for name in names: - obj = getattr(Source, name) - if type(obj) == type(get_attributes): - obj = staticmethod(obj) - d[name] = obj - return d - def create_test_cases(Mixin, type): result = {} glob = globals() @@ -2975,10 +2940,10 @@ assert set(base.ALLOWED_TYPES) <= ALL_TYPES, set(base.ALLOWED_TYPES) if type in base.ALLOWED_TYPES: newname = 'With' + Type + name[1:] - class Temp(base, unittest.TestCase, Mixin): + class Temp(base, Mixin, unittest.TestCase): pass result[newname] = Temp - Temp.__name__ = newname + Temp.__name__ = Temp.__qualname__ = newname Temp.__module__ = Mixin.__module__ return result @@ -2989,12 +2954,24 @@ class ProcessesMixin(object): TYPE = 'processes' Process = multiprocessing.Process - locals().update(get_attributes(multiprocessing, ( - 'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', - 'Condition', 'Event', 'Barrier', 'Value', 'Array', 'RawValue', - 'RawArray', 'current_process', 'active_children', 'Pipe', - 'connection', 'JoinableQueue', 'Pool' - ))) + connection = multiprocessing.connection + current_process = staticmethod(multiprocessing.current_process) + active_children = staticmethod(multiprocessing.active_children) + Pool = staticmethod(multiprocessing.Pool) + Pipe = staticmethod(multiprocessing.Pipe) + Queue = staticmethod(multiprocessing.Queue) + JoinableQueue = staticmethod(multiprocessing.JoinableQueue) + Lock = staticmethod(multiprocessing.Lock) + RLock = staticmethod(multiprocessing.RLock) + Semaphore = staticmethod(multiprocessing.Semaphore) + BoundedSemaphore = staticmethod(multiprocessing.BoundedSemaphore) + Condition = staticmethod(multiprocessing.Condition) + Event = staticmethod(multiprocessing.Event) + Barrier = staticmethod(multiprocessing.Barrier) + Value = staticmethod(multiprocessing.Value) + Array = staticmethod(multiprocessing.Array) + RawValue = staticmethod(multiprocessing.RawValue) + RawArray = staticmethod(multiprocessing.RawArray) testcases_processes = create_test_cases(ProcessesMixin, type='processes') globals().update(testcases_processes) @@ -3003,12 +2980,48 @@ class ManagerMixin(object): TYPE = 'manager' Process = multiprocessing.Process - manager = object.__new__(multiprocessing.managers.SyncManager) - locals().update(get_attributes(manager, ( - 'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', - 'Condition', 'Event', 'Barrier', 'Value', 'Array', 'list', 'dict', - 'Namespace', 'JoinableQueue', 'Pool' - ))) + Queue = property(operator.attrgetter('manager.Queue')) + JoinableQueue = property(operator.attrgetter('manager.JoinableQueue')) + Lock = property(operator.attrgetter('manager.Lock')) + RLock = property(operator.attrgetter('manager.RLock')) + Semaphore = property(operator.attrgetter('manager.Semaphore')) + BoundedSemaphore = property(operator.attrgetter('manager.BoundedSemaphore')) + Condition = property(operator.attrgetter('manager.Condition')) + Event = property(operator.attrgetter('manager.Event')) + Barrier = property(operator.attrgetter('manager.Barrier')) + Value = property(operator.attrgetter('manager.Value')) + Array = property(operator.attrgetter('manager.Array')) + list = property(operator.attrgetter('manager.list')) + dict = property(operator.attrgetter('manager.dict')) + Namespace = property(operator.attrgetter('manager.Namespace')) + + @classmethod + def Pool(cls, *args, **kwds): + return cls.manager.Pool(*args, **kwds) + + @classmethod + def setUpClass(cls): + cls.manager = multiprocessing.Manager() + + @classmethod + def tearDownClass(cls): + # only the manager process should be returned by active_children() + # but this can take a bit on slow machines, so wait a few seconds + # if there are other children too (see #17395) + t = 0.01 + while len(multiprocessing.active_children()) > 1 and t < 5: + time.sleep(t) + t *= 2 + gc.collect() # do garbage collection + if cls.manager._number_of_objects() != 0: + # This is not really an error since some tests do not + # ensure that all processes which hold a reference to a + # managed object have been joined. + print('Shared objects which still exist at manager shutdown:') + print(cls.manager._debug_info()) + cls.manager.shutdown() + cls.manager.join() + cls.manager = None testcases_manager = create_test_cases(ManagerMixin, type='manager') globals().update(testcases_manager) @@ -3017,16 +3030,27 @@ class ThreadsMixin(object): TYPE = 'threads' Process = multiprocessing.dummy.Process - locals().update(get_attributes(multiprocessing.dummy, ( - 'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', - 'Condition', 'Event', 'Barrier', 'Value', 'Array', 'current_process', - 'active_children', 'Pipe', 'connection', 'dict', 'list', - 'Namespace', 'JoinableQueue', 'Pool' - ))) + connection = multiprocessing.dummy.connection + current_process = staticmethod(multiprocessing.dummy.current_process) + active_children = staticmethod(multiprocessing.dummy.active_children) + Pool = staticmethod(multiprocessing.Pool) + Pipe = staticmethod(multiprocessing.dummy.Pipe) + Queue = staticmethod(multiprocessing.dummy.Queue) + JoinableQueue = staticmethod(multiprocessing.dummy.JoinableQueue) + Lock = staticmethod(multiprocessing.dummy.Lock) + RLock = staticmethod(multiprocessing.dummy.RLock) + Semaphore = staticmethod(multiprocessing.dummy.Semaphore) + BoundedSemaphore = staticmethod(multiprocessing.dummy.BoundedSemaphore) + Condition = staticmethod(multiprocessing.dummy.Condition) + Event = staticmethod(multiprocessing.dummy.Event) + Barrier = staticmethod(multiprocessing.dummy.Barrier) + Value = staticmethod(multiprocessing.dummy.Value) + Array = staticmethod(multiprocessing.dummy.Array) testcases_threads = create_test_cases(ThreadsMixin, type='threads') globals().update(testcases_threads) + class OtherTest(unittest.TestCase): # TODO: add more tests for deliver/answer challenge. def test_deliver_challenge_auth_failure(self): @@ -3532,16 +3556,7 @@ # # -testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, - TestStdinBadfiledescriptor, TestWait, TestInvalidFamily, - TestFlags, TestTimeouts, TestNoForkBomb, - TestForkAwareThreadLock, TestIgnoreEINTR] - -# -# -# - -def test_main(run=None): +def setUpModule(): if sys.platform.startswith("linux"): try: lock = multiprocessing.RLock() @@ -3550,43 +3565,10 @@ check_enough_semaphores() - if run is None: - from test.support import run_unittest as run - util.get_temp_dir() # creates temp directory for use by all processes multiprocessing.get_logger().setLevel(LOG_LEVEL) - ProcessesMixin.pool = multiprocessing.Pool(4) - ThreadsMixin.pool = multiprocessing.dummy.Pool(4) - ManagerMixin.manager.__init__() - ManagerMixin.manager.start() - ManagerMixin.pool = ManagerMixin.manager.Pool(4) - - testcases = ( - sorted(testcases_processes.values(), key=lambda tc:tc.__name__) + - sorted(testcases_threads.values(), key=lambda tc:tc.__name__) + - sorted(testcases_manager.values(), key=lambda tc:tc.__name__) + - testcases_other - ) - - loadTestsFromTestCase = unittest.defaultTestLoader.loadTestsFromTestCase - suite = unittest.TestSuite(loadTestsFromTestCase(tc) for tc in testcases) - try: - run(suite) - finally: - ThreadsMixin.pool.terminate() - ProcessesMixin.pool.terminate() - ManagerMixin.pool.terminate() - ManagerMixin.pool.join() - ManagerMixin.manager.shutdown() - ManagerMixin.manager.join() - ThreadsMixin.pool.join() - ProcessesMixin.pool.join() - del ProcessesMixin.pool, ThreadsMixin.pool, ManagerMixin.pool - -def main(): - test_main(unittest.TextTestRunner(verbosity=2).run) if __name__ == '__main__': - main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,9 @@ Library ------- +- Issue #17778: Fix test discovery for test_multiprocessing. (Patch by + Zachary Ware.) + - Issue #18431: The new email header parser now decodes RFC2047 encoded words in structured headers. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 16:58:46 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 16 Jul 2013 16:58:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317778=3A_Fix_test_discovery_for_test=5Fmultipro?= =?utf-8?q?cessing=2E_=28Patch_by?= Message-ID: <3bvl9f0Zmxz7LmF@mail.python.org> http://hg.python.org/cpython/rev/c704735487ae changeset: 84661:c704735487ae parent: 84657:7272ef213b7c parent: 84660:8a922b28b97d user: Richard Oudkerk date: Tue Jul 16 15:57:16 2013 +0100 summary: Issue #17778: Fix test discovery for test_multiprocessing. (Patch by Zachary Ware.) files: Lib/test/test_multiprocessing.py | 31 +------------------ Misc/NEWS | 10 ++++- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -2404,7 +2404,7 @@ c.close() l.close() -class _TestPoll(unittest.TestCase): +class _TestPoll(BaseTestCase): ALLOWED_TYPES = ('processes', 'threads') @@ -3585,16 +3585,7 @@ # # -testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, - TestStdinBadfiledescriptor, TestWait, TestInvalidFamily, - TestFlags, TestTimeouts, TestNoForkBomb, - TestForkAwareThreadLock, TestIgnoreEINTR] - -# -# -# - -def test_main(run=None): +def setUpModule(): if sys.platform.startswith("linux"): try: lock = multiprocessing.RLock() @@ -3603,26 +3594,10 @@ check_enough_semaphores() - if run is None: - from test.support import run_unittest as run - util.get_temp_dir() # creates temp directory for use by all processes multiprocessing.get_logger().setLevel(LOG_LEVEL) - testcases = ( - sorted(testcases_processes.values(), key=lambda tc:tc.__name__) + - sorted(testcases_threads.values(), key=lambda tc:tc.__name__) + - sorted(testcases_manager.values(), key=lambda tc:tc.__name__) + - testcases_other - ) - - loadTestsFromTestCase = unittest.defaultTestLoader.loadTestsFromTestCase - suite = unittest.TestSuite(loadTestsFromTestCase(tc) for tc in testcases) - run(suite) - -def main(): - test_main(unittest.TextTestRunner(verbosity=2).run) if __name__ == '__main__': - main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -156,9 +156,13 @@ Library ------- -- Issue #18393: The private module _gestalt and private functions platform._mac_ver_gestalt, - platform._mac_ver_lookup and platform._bcd2str have been removed. This does not - affect the public interface of the platform module. +- Issue #17778: Fix test discovery for test_multiprocessing. (Patch by + Zachary Ware.) + +- Issue #18393: The private module _gestalt and private functions + platform._mac_ver_gestalt, platform._mac_ver_lookup and + platform._bcd2str have been removed. This does not affect the public + interface of the platform module. - Issue #17482: functools.update_wrapper (and functools.wraps) now set the __wrapped__ attribute correctly even if the underlying function has a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 17:46:25 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 16 Jul 2013 17:46:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogQ2xvc2VzICMxODQ3?= =?utf-8?q?5=3A_add_unittest=2Emain=28=29_to_test=5Femail/test=5Finversion?= =?utf-8?q?s=2E?= Message-ID: <3bvmDd4qmbz7Lm4@mail.python.org> http://hg.python.org/cpython/rev/b92db0aebc42 changeset: 84662:b92db0aebc42 branch: 3.3 parent: 84660:8a922b28b97d user: R David Murray date: Tue Jul 16 11:45:31 2013 -0400 summary: Closes #18475: add unittest.main() to test_email/test_inversions. Patch by Vajrasky Kok. files: Lib/test/test_email/test_inversion.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_email/test_inversion.py b/Lib/test/test_email/test_inversion.py --- a/Lib/test/test_email/test_inversion.py +++ b/Lib/test/test_email/test_inversion.py @@ -43,3 +43,7 @@ """),), } + + +if __name__ == '__main__': + unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 17:46:27 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 16 Jul 2013 17:46:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_Closes_=2318475=3A_add_unittest=2Emain=28=29_to?= =?utf-8?q?_test=5Femail/test=5Finversions=2E?= Message-ID: <3bvmDg0JW9zS35@mail.python.org> http://hg.python.org/cpython/rev/48f27b745519 changeset: 84663:48f27b745519 parent: 84661:c704735487ae parent: 84662:b92db0aebc42 user: R David Murray date: Tue Jul 16 11:46:00 2013 -0400 summary: Merge: Closes #18475: add unittest.main() to test_email/test_inversions. files: Lib/test/test_email/test_inversion.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_email/test_inversion.py b/Lib/test/test_email/test_inversion.py --- a/Lib/test/test_email/test_inversion.py +++ b/Lib/test/test_email/test_inversion.py @@ -43,3 +43,7 @@ """),), } + + +if __name__ == '__main__': + unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 20:59:44 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 16 Jul 2013 20:59:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDU3?= =?utf-8?q?=3A_Fixed_saving_of_formulas_and_complex_numbers_in_Tools/demo/?= =?utf-8?q?ss1=2Epy=2E?= Message-ID: <3bvrWh12y4z7LkV@mail.python.org> http://hg.python.org/cpython/rev/9098a4ad4d3e changeset: 84664:9098a4ad4d3e branch: 3.3 parent: 84662:b92db0aebc42 user: Serhiy Storchaka date: Tue Jul 16 21:55:36 2013 +0300 summary: Issue #18457: Fixed saving of formulas and complex numbers in Tools/demo/ss1.py. Useed context managers for file I/O. Removed out-of-dated code and misleading comments. files: Misc/NEWS | 3 ++ Tools/demo/ss1.py | 52 ++++++++++++---------------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -229,6 +229,9 @@ Tools/Demos ----------- +- Issue #18457: Fixed saving of formulas and complex numbers in + Tools/demo/ss1.py. + - Issue #18449: Make Tools/demo/ss1.py work again on Python 3. Patch by F?vry Thibault. diff --git a/Tools/demo/ss1.py b/Tools/demo/ss1.py --- a/Tools/demo/ss1.py +++ b/Tools/demo/ss1.py @@ -7,8 +7,8 @@ import os import re import sys -import html from xml.parsers import expat +from xml.sax.saxutils import escape LEFT, CENTER, RIGHT = "LEFT", "CENTER", "RIGHT" @@ -205,7 +205,7 @@ if hasattr(cell, 'xml'): cellxml = cell.xml() else: - cellxml = '%s' % html.escape(cell) + cellxml = '%s' % escape(cell) out.append('\n %s\n' % (y, x, cellxml)) out.append('') @@ -213,16 +213,14 @@ def save(self, filename): text = self.xml() - f = open(filename, "w") - f.write(text) - if text and not text.endswith('\n'): - f.write('\n') - f.close() + with open(filename, "w", encoding='utf-8') as f: + f.write(text) + if text and not text.endswith('\n'): + f.write('\n') def load(self, filename): - f = open(filename, 'rb') - SheetParser(self).parsefile(f) - f.close() + with open(filename, 'rb') as f: + SheetParser(self).parsefile(f) class SheetParser: @@ -239,13 +237,10 @@ def startelement(self, tag, attrs): method = getattr(self, 'start_'+tag, None) if method: - for key, value in attrs.items(): - attrs[key] = str(value) # XXX Convert Unicode to 8-bit method(attrs) self.texts = [] def data(self, text): - text = str(text) # XXX Convert Unicode to 8-bit self.texts.append(text) def endelement(self, tag): @@ -269,11 +264,7 @@ except: self.value = None - def end_long(self, text): - try: - self.value = int(text) - except: - self.value = None + end_long = end_int def end_double(self, text): try: @@ -288,10 +279,7 @@ self.value = None def end_string(self, text): - try: - self.value = text - except: - self.value = None + self.value = text def end_value(self, text): if isinstance(self.value, BaseCell): @@ -328,7 +316,7 @@ class NumericCell(BaseCell): def __init__(self, value, fmt="%s", alignment=RIGHT): - assert isinstance(value, (int, int, float, complex)) + assert isinstance(value, (int, float, complex)) assert alignment in (LEFT, CENTER, RIGHT) self.value = value self.fmt = fmt @@ -355,21 +343,18 @@ if -2**31 <= self.value < 2**31: return '%s' % self.value else: - return self._xml_long() - - def _xml_long(self): - return '%s' % self.value + return '%s' % self.value def _xml_float(self): - return '%s' % repr(self.value) + return '%r' % self.value def _xml_complex(self): - return '%s' % repr(self.value) + return '%r' % self.value class StringCell(BaseCell): def __init__(self, text, fmt="%s", alignment=LEFT): - assert isinstance(text, (str, str)) + assert isinstance(text, str) assert alignment in (LEFT, CENTER, RIGHT) self.text = text self.fmt = fmt @@ -386,7 +371,7 @@ return s % ( align2xml[self.alignment], self.fmt, - html.escape(self.text)) + escape(self.text)) class FormulaCell(BaseCell): @@ -404,7 +389,6 @@ def recalc(self, ns): if self.value is None: try: - # A hack to evaluate expressions using true division self.value = eval(self.translated, ns) except: exc = sys.exc_info()[0] @@ -425,7 +409,7 @@ return '%s' % ( align2xml[self.alignment], self.fmt, - self.formula) + escape(self.formula)) def renumber(self, x1, y1, x2, y2, dx, dy): out = [] @@ -776,7 +760,7 @@ if text.startswith('='): cell = FormulaCell(text[1:]) else: - for cls in int, int, float, complex: + for cls in int, float, complex: try: value = cls(text) except: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 20:59:45 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 16 Jul 2013 20:59:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318457=3A_Fixed_saving_of_formulas_and_complex_n?= =?utf-8?q?umbers_in_Tools/demo/ss1=2Epy=2E?= Message-ID: <3bvrWj4GZSz7Ll6@mail.python.org> http://hg.python.org/cpython/rev/c6b91d894577 changeset: 84665:c6b91d894577 parent: 84663:48f27b745519 parent: 84664:9098a4ad4d3e user: Serhiy Storchaka date: Tue Jul 16 21:58:37 2013 +0300 summary: Issue #18457: Fixed saving of formulas and complex numbers in Tools/demo/ss1.py. Useed context managers for file I/O. Removed out-of-dated code and misleading comments. files: Misc/NEWS | 3 ++ Tools/demo/ss1.py | 52 ++++++++++++---------------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -673,6 +673,9 @@ Tools/Demos ----------- +- Issue #18457: Fixed saving of formulas and complex numbers in + Tools/demo/ss1.py. + - Issue #18449: Make Tools/demo/ss1.py work again on Python 3. Patch by F?vry Thibault. diff --git a/Tools/demo/ss1.py b/Tools/demo/ss1.py --- a/Tools/demo/ss1.py +++ b/Tools/demo/ss1.py @@ -7,8 +7,8 @@ import os import re import sys -import html from xml.parsers import expat +from xml.sax.saxutils import escape LEFT, CENTER, RIGHT = "LEFT", "CENTER", "RIGHT" @@ -205,7 +205,7 @@ if hasattr(cell, 'xml'): cellxml = cell.xml() else: - cellxml = '%s' % html.escape(cell) + cellxml = '%s' % escape(cell) out.append('\n %s\n' % (y, x, cellxml)) out.append('') @@ -213,16 +213,14 @@ def save(self, filename): text = self.xml() - f = open(filename, "w") - f.write(text) - if text and not text.endswith('\n'): - f.write('\n') - f.close() + with open(filename, "w", encoding='utf-8') as f: + f.write(text) + if text and not text.endswith('\n'): + f.write('\n') def load(self, filename): - f = open(filename, 'rb') - SheetParser(self).parsefile(f) - f.close() + with open(filename, 'rb') as f: + SheetParser(self).parsefile(f) class SheetParser: @@ -239,13 +237,10 @@ def startelement(self, tag, attrs): method = getattr(self, 'start_'+tag, None) if method: - for key, value in attrs.items(): - attrs[key] = str(value) # XXX Convert Unicode to 8-bit method(attrs) self.texts = [] def data(self, text): - text = str(text) # XXX Convert Unicode to 8-bit self.texts.append(text) def endelement(self, tag): @@ -269,11 +264,7 @@ except: self.value = None - def end_long(self, text): - try: - self.value = int(text) - except: - self.value = None + end_long = end_int def end_double(self, text): try: @@ -288,10 +279,7 @@ self.value = None def end_string(self, text): - try: - self.value = text - except: - self.value = None + self.value = text def end_value(self, text): if isinstance(self.value, BaseCell): @@ -328,7 +316,7 @@ class NumericCell(BaseCell): def __init__(self, value, fmt="%s", alignment=RIGHT): - assert isinstance(value, (int, int, float, complex)) + assert isinstance(value, (int, float, complex)) assert alignment in (LEFT, CENTER, RIGHT) self.value = value self.fmt = fmt @@ -355,21 +343,18 @@ if -2**31 <= self.value < 2**31: return '%s' % self.value else: - return self._xml_long() - - def _xml_long(self): - return '%s' % self.value + return '%s' % self.value def _xml_float(self): - return '%s' % repr(self.value) + return '%r' % self.value def _xml_complex(self): - return '%s' % repr(self.value) + return '%r' % self.value class StringCell(BaseCell): def __init__(self, text, fmt="%s", alignment=LEFT): - assert isinstance(text, (str, str)) + assert isinstance(text, str) assert alignment in (LEFT, CENTER, RIGHT) self.text = text self.fmt = fmt @@ -386,7 +371,7 @@ return s % ( align2xml[self.alignment], self.fmt, - html.escape(self.text)) + escape(self.text)) class FormulaCell(BaseCell): @@ -404,7 +389,6 @@ def recalc(self, ns): if self.value is None: try: - # A hack to evaluate expressions using true division self.value = eval(self.translated, ns) except: exc = sys.exc_info()[0] @@ -425,7 +409,7 @@ return '%s' % ( align2xml[self.alignment], self.fmt, - self.formula) + escape(self.formula)) def renumber(self, x1, y1, x2, y2, dx, dy): out = [] @@ -776,7 +760,7 @@ if text.startswith('='): cell = FormulaCell(text[1:]) else: - for cls in int, int, float, complex: + for cls in int, float, complex: try: value = cls(text) except: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 21:16:35 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 16 Jul 2013 21:16:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQ4?= =?utf-8?q?=3A_Fix_a_typo_in_Demo/newmetaclasses/Eiffel=2Epy=2E?= Message-ID: <3bvrv76NB2zSg0@mail.python.org> http://hg.python.org/cpython/rev/a9f7c2d49149 changeset: 84666:a9f7c2d49149 branch: 2.7 parent: 84659:d635e94948a6 user: Serhiy Storchaka date: Tue Jul 16 22:11:28 2013 +0300 summary: Issue #18448: Fix a typo in Demo/newmetaclasses/Eiffel.py. files: Demo/newmetaclasses/Eiffel.py | 2 +- Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Demo/newmetaclasses/Eiffel.py b/Demo/newmetaclasses/Eiffel.py --- a/Demo/newmetaclasses/Eiffel.py +++ b/Demo/newmetaclasses/Eiffel.py @@ -29,7 +29,7 @@ pre = dict.get("%s_pre" % m) post = dict.get("%s_post" % m) if pre or post: - dict[k] = cls.make_eiffel_method(dict[m], pre, post) + dict[m] = cls.make_eiffel_method(dict[m], pre, post) class EiffelMetaClass1(EiffelBaseMetaClass): # an implementation of the "eiffel" meta class that uses nested functions diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -77,6 +77,8 @@ Tools/Demos ----------- +- Issue #18448: Fix a typo in Demo/newmetaclasses/Eiffel.py. + - Issue #12990: The "Python Launcher" on OSX could not launch python scripts that have paths that include wide characters. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 21:16:37 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 16 Jul 2013 21:16:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDQ4?= =?utf-8?q?=3A_Fix_a_typo_in_Tools/demo/eiffel=2Epy=2E?= Message-ID: <3bvrv91J7Pz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/6e8ad6071100 changeset: 84667:6e8ad6071100 branch: 3.3 parent: 84664:9098a4ad4d3e user: Serhiy Storchaka date: Tue Jul 16 22:12:03 2013 +0300 summary: Issue #18448: Fix a typo in Tools/demo/eiffel.py. files: Misc/NEWS | 2 ++ Tools/demo/eiffel.py | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -229,6 +229,8 @@ Tools/Demos ----------- +- Issue #18448: Fix a typo in Tools/demo/eiffel.py. + - Issue #18457: Fixed saving of formulas and complex numbers in Tools/demo/ss1.py. diff --git a/Tools/demo/eiffel.py b/Tools/demo/eiffel.py --- a/Tools/demo/eiffel.py +++ b/Tools/demo/eiffel.py @@ -36,7 +36,7 @@ pre = dict.get("%s_pre" % m) post = dict.get("%s_post" % m) if pre or post: - dict[k] = cls.make_eiffel_method(dict[m], pre, post) + dict[m] = cls.make_eiffel_method(dict[m], pre, post) class EiffelMetaClass1(EiffelBaseMetaClass): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 21:16:38 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 16 Jul 2013 21:16:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318448=3A_Fix_a_typo_in_Tools/demo/eiffel=2Epy?= =?utf-8?q?=2E?= Message-ID: <3bvrvB3KnGz7Ll8@mail.python.org> http://hg.python.org/cpython/rev/128618d2589c changeset: 84668:128618d2589c parent: 84665:c6b91d894577 parent: 84667:6e8ad6071100 user: Serhiy Storchaka date: Tue Jul 16 22:14:03 2013 +0300 summary: Issue #18448: Fix a typo in Tools/demo/eiffel.py. files: Misc/NEWS | 2 ++ Tools/demo/eiffel.py | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -673,6 +673,8 @@ Tools/Demos ----------- +- Issue #18448: Fix a typo in Tools/demo/eiffel.py. + - Issue #18457: Fixed saving of formulas and complex numbers in Tools/demo/ss1.py. diff --git a/Tools/demo/eiffel.py b/Tools/demo/eiffel.py --- a/Tools/demo/eiffel.py +++ b/Tools/demo/eiffel.py @@ -36,7 +36,7 @@ pre = dict.get("%s_pre" % m) post = dict.get("%s_post" % m) if pre or post: - dict[k] = cls.make_eiffel_method(dict[m], pre, post) + dict[m] = cls.make_eiffel_method(dict[m], pre, post) class EiffelMetaClass1(EiffelBaseMetaClass): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 23:09:15 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 23:09:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_file?= =?utf-8?q?io=5Fread=28=29_on_=5FPyBytes=5FResize=28=29_failure?= Message-ID: <3bvvP70WNXz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/533eb9ab895a changeset: 84669:533eb9ab895a user: Victor Stinner date: Tue Jul 16 21:36:02 2013 +0200 summary: Issue #18408: Fix fileio_read() on _PyBytes_Resize() failure bytes is NULL on _PyBytes_Resize() failure 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 @@ -739,7 +739,7 @@ if (n != size) { if (_PyBytes_Resize(&bytes, n) < 0) { - Py_DECREF(bytes); + Py_CLEAR(bytes); return NULL; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 23:09:16 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 23:09:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_cjkc?= =?utf-8?q?odecs_decoders=2C_add_a_new_MBERR=5FEXCEPTION_constant_to?= Message-ID: <3bvvP82Pxgz7Lkd@mail.python.org> http://hg.python.org/cpython/rev/f0efd7ea1627 changeset: 84670:f0efd7ea1627 user: Victor Stinner date: Tue Jul 16 21:41:43 2013 +0200 summary: Issue #18408: Fix cjkcodecs decoders, add a new MBERR_EXCEPTION constant to notify exceptions raised by the _PyUnicodeWriter API files: Modules/cjkcodecs/cjkcodecs.h | 4 ++-- Modules/cjkcodecs/multibytecodec.c | 2 ++ Modules/cjkcodecs/multibytecodec.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h --- a/Modules/cjkcodecs/cjkcodecs.h +++ b/Modules/cjkcodecs/cjkcodecs.h @@ -130,7 +130,7 @@ #define OUTCHAR(c) \ do { \ if (_PyUnicodeWriter_WriteChar(writer, (c)) < 0) \ - return MBERR_TOOSMALL; \ + return MBERR_EXCEPTION; \ } while (0) #define OUTCHAR2(c1, c2) \ @@ -138,7 +138,7 @@ Py_UCS4 _c1 = (c1); \ Py_UCS4 _c2 = (c2); \ if (_PyUnicodeWriter_Prepare(writer, 2, Py_MAX(_c1, c2)) < 0) \ - return MBERR_TOOSMALL; \ + return MBERR_EXCEPTION; \ PyUnicode_WRITE(writer->kind, writer->data, writer->pos, _c1); \ PyUnicode_WRITE(writer->kind, writer->data, writer->pos + 1, _c2); \ writer->pos += 2; \ diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -384,6 +384,8 @@ PyErr_SetString(PyExc_RuntimeError, "internal codec error"); return -1; + case MBERR_EXCEPTION: + return -1; default: PyErr_SetString(PyExc_RuntimeError, "unknown runtime error"); diff --git a/Modules/cjkcodecs/multibytecodec.h b/Modules/cjkcodecs/multibytecodec.h --- a/Modules/cjkcodecs/multibytecodec.h +++ b/Modules/cjkcodecs/multibytecodec.h @@ -112,6 +112,7 @@ #define MBERR_TOOSMALL (-1) /* insufficient output buffer space */ #define MBERR_TOOFEW (-2) /* incomplete input buffer */ #define MBERR_INTERNAL (-3) /* internal runtime error */ +#define MBERR_EXCEPTION (-4) /* an exception has been raised */ #define ERROR_STRICT (PyObject *)(1) #define ERROR_IGNORE (PyObject *)(2) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 23:09:17 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 23:09:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_list?= =?utf-8?b?LmV4dGVuZCgpLCBoYW5kbGUgbGlzdF9yZXNpemUoKSBmYWlsdXJl?= Message-ID: <3bvvP94K2Gz7Ll5@mail.python.org> http://hg.python.org/cpython/rev/395e67f348e7 changeset: 84671:395e67f348e7 user: Victor Stinner date: Tue Jul 16 21:45:58 2013 +0200 summary: Issue #18408: Fix list.extend(), handle list_resize() failure files: Objects/listobject.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -871,8 +871,10 @@ } /* Cut back result list if initial guess was too large. */ - if (Py_SIZE(self) < self->allocated) - list_resize(self, Py_SIZE(self)); /* shrinking can't fail */ + if (Py_SIZE(self) < self->allocated) { + if (list_resize(self, Py_SIZE(self)) < 0) + goto error; + } Py_DECREF(it); Py_RETURN_NONE; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 23:09:18 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 23:09:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_PyDi?= =?utf-8?q?ct=5FGetItemString=28=29=2C_suppress_PyUnicode=5FFromString=28?= =?utf-8?q?=29_error?= Message-ID: <3bvvPB64C4z7LlH@mail.python.org> http://hg.python.org/cpython/rev/ac4e8e6a7436 changeset: 84672:ac4e8e6a7436 user: Victor Stinner date: Tue Jul 16 22:16:05 2013 +0200 summary: Issue #18408: Fix PyDict_GetItemString(), suppress PyUnicode_FromString() error As PyDict_GetItem(), PyDict_GetItemString() suppresses all errors that may occur for historical reasons. files: Objects/dictobject.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2692,8 +2692,10 @@ { PyObject *kv, *rv; kv = PyUnicode_FromString(key); - if (kv == NULL) + if (kv == NULL) { + PyErr_Clear(); return NULL; + } rv = PyDict_GetItem(v, kv); Py_DECREF(kv); return rv; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 23:09:20 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 23:09:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Cleanup_dictobject=2Ec?= Message-ID: <3bvvPD0rR1z7Ll8@mail.python.org> http://hg.python.org/cpython/rev/5beb1f12f19f changeset: 84673:5beb1f12f19f user: Victor Stinner date: Tue Jul 16 22:17:26 2013 +0200 summary: Cleanup dictobject.c files: Objects/dictobject.c | 34 ++++++++++++++++--------------- 1 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -305,9 +305,9 @@ * #define USABLE_FRACTION(n) (((n) >> 1) + ((n) >> 2) - ((n) >> 3)) */ -/* 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, +/* 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 @@ -2589,23 +2589,25 @@ dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *self; + PyDictObject *d; assert(type != NULL && type->tp_alloc != NULL); self = type->tp_alloc(type, 0); - if (self != NULL) { - PyDictObject *d = (PyDictObject *)self; - d->ma_keys = new_keys_object(PyDict_MINSIZE_COMBINED); - /* XXX - Should we raise a no-memory error? */ - if (d->ma_keys == NULL) { - DK_INCREF(Py_EMPTY_KEYS); - d->ma_keys = Py_EMPTY_KEYS; - d->ma_values = empty_values; - } - d->ma_used = 0; - /* The object has been implicitly tracked by tp_alloc */ - if (type == &PyDict_Type) - _PyObject_GC_UNTRACK(d); + if (self == NULL) + return NULL; + + d = (PyDictObject *)self; + d->ma_keys = new_keys_object(PyDict_MINSIZE_COMBINED); + /* XXX - Should we raise a no-memory error? */ + if (d->ma_keys == NULL) { + DK_INCREF(Py_EMPTY_KEYS); + d->ma_keys = Py_EMPTY_KEYS; + d->ma_values = empty_values; } + d->ma_used = 0; + /* The object has been implicitly tracked by tp_alloc */ + if (type == &PyDict_Type) + _PyObject_GC_UNTRACK(d); return self; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 23:09:21 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 23:09:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_dict=5Fn?= =?utf-8?q?ew=28=29_now_fails_on_new=5Fkeys=5Fobject=28=29_error?= Message-ID: <3bvvPF2hRFz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/b7c6d203c9fb changeset: 84674:b7c6d203c9fb user: Victor Stinner date: Tue Jul 16 22:19:00 2013 +0200 summary: Issue #18408: dict_new() now fails on new_keys_object() error Pass the MemoryError exception to the caller, instead of using empty keys. files: Objects/dictobject.c | 19 +++++++++---------- 1 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1395,7 +1395,7 @@ } DK_DECREF(keys); } - else { + else if (keys != NULL) { assert(keys->dk_refcnt == 1); DK_DECREF(keys); } @@ -2595,19 +2595,18 @@ self = type->tp_alloc(type, 0); if (self == NULL) return NULL; - d = (PyDictObject *)self; - d->ma_keys = new_keys_object(PyDict_MINSIZE_COMBINED); - /* XXX - Should we raise a no-memory error? */ - if (d->ma_keys == NULL) { - DK_INCREF(Py_EMPTY_KEYS); - d->ma_keys = Py_EMPTY_KEYS; - d->ma_values = empty_values; - } - d->ma_used = 0; + /* The object has been implicitly tracked by tp_alloc */ if (type == &PyDict_Type) _PyObject_GC_UNTRACK(d); + + d->ma_used = 0; + d->ma_keys = new_keys_object(PyDict_MINSIZE_COMBINED); + if (d->ma_keys == NULL) { + Py_DECREF(self); + return NULL; + } return self; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 23:09:22 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 23:09:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Py=5FRep?= =?utf-8?q?rLeave=28=29_now_saves/restores_the_current_exception=2C?= Message-ID: <3bvvPG4VdKz7LlH@mail.python.org> http://hg.python.org/cpython/rev/28ff7ac91477 changeset: 84675:28ff7ac91477 user: Victor Stinner date: Tue Jul 16 22:24:44 2013 +0200 summary: Issue #18408: Py_ReprLeave() now saves/restores the current exception, and ignores exceptions raised during the call files: Objects/object.c | 13 +++++++++++-- 1 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -1920,13 +1920,18 @@ PyObject *dict; PyObject *list; Py_ssize_t i; + PyObject *error_type, *error_value, *error_traceback; + + PyErr_Fetch(&error_type, &error_value, &error_traceback); dict = PyThreadState_GetDict(); if (dict == NULL) - return; + goto finally; + list = PyDict_GetItemString(dict, KEY); if (list == NULL || !PyList_Check(list)) - return; + goto finally; + i = PyList_GET_SIZE(list); /* Count backwards because we always expect obj to be list[-1] */ while (--i >= 0) { @@ -1935,6 +1940,10 @@ break; } } + +finally: + /* ignore exceptions because there is no way to report them. */ + PyErr_Restore(error_type, error_value, error_traceback); } /* Trashcan support. */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 23:09:23 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 23:09:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_handle_P?= =?utf-8?q?ySys=5FGetObject=28=29_failure=2C_raise_a_RuntimeError?= Message-ID: <3bvvPH6X0Nz7Ll2@mail.python.org> http://hg.python.org/cpython/rev/6bd01a59762a changeset: 84676:6bd01a59762a user: Victor Stinner date: Tue Jul 16 22:26:05 2013 +0200 summary: Issue #18408: handle PySys_GetObject() failure, raise a RuntimeError files: Modules/_pickle.c | 8 ++++++-- Modules/main.c | 4 +++- Python/bltinmodule.c | 5 +++++ Python/import.c | 14 ++++++++------ 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1361,8 +1361,10 @@ search: modules_dict = PySys_GetObject("modules"); - if (modules_dict == NULL) + if (modules_dict == NULL) { + PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules"); return NULL; + } i = 0; module_name = NULL; @@ -5542,8 +5544,10 @@ } modules_dict = PySys_GetObject("modules"); - if (modules_dict == NULL) + if (modules_dict == NULL) { + PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules"); return NULL; + } module = PyDict_GetItemWithError(modules_dict, module_name); if (module == NULL) { diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -260,8 +260,10 @@ /* argv0 is usable as an import source, so put it in sys.path[0] and import __main__ */ sys_path = PySys_GetObject("path"); - if (sys_path == NULL) + if (sys_path == NULL) { + PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path"); goto error; + } if (PyList_SetItem(sys_path, 0, argv0)) { argv0 = NULL; goto error; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1550,6 +1550,11 @@ return NULL; if (file == NULL || file == Py_None) { file = PySys_GetObject("stdout"); + if (file == NULL) { + PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout"); + return NULL; + } + /* sys.stdout may be None when FILE* stdout isn't connected */ if (file == Py_None) Py_RETURN_NONE; diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -85,8 +85,10 @@ int err = 0; path_hooks = PySys_GetObject("path_hooks"); - if (path_hooks == NULL) + if (path_hooks == NULL) { + PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path_hooks"); goto error; + } if (Py_VerboseFlag) PySys_WriteStderr("# installing zipimport hook\n"); @@ -944,11 +946,11 @@ PyImport_GetImporter(PyObject *path) { PyObject *importer=NULL, *path_importer_cache=NULL, *path_hooks=NULL; - if ((path_importer_cache = PySys_GetObject("path_importer_cache"))) { - if ((path_hooks = PySys_GetObject("path_hooks"))) { - importer = get_path_importer(path_importer_cache, - path_hooks, path); - } + path_importer_cache = PySys_GetObject("path_importer_cache"); + path_hooks = PySys_GetObject("path_hooks"); + if (path_importer_cache != NULL && path_hooks != NULL) { + importer = get_path_importer(path_importer_cache, + path_hooks, path); } Py_XINCREF(importer); /* get_path_importer returns a borrowed reference */ return importer; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 16 23:09:25 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 16 Jul 2013 23:09:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Cleanup_type=5Fcall=28=29_?= =?utf-8?q?to_ease_debug?= Message-ID: <3bvvPK1Mhxz7LlH@mail.python.org> http://hg.python.org/cpython/rev/ffd3c6ee2a3a changeset: 84677:ffd3c6ee2a3a user: Victor Stinner date: Tue Jul 16 22:51:21 2013 +0200 summary: Cleanup type_call() to ease debug It was easy to miss the call to type->tp_init because it was done in a long conditional expression. Split the long expression in multiple lines to make the debug step by step easier. files: Objects/typeobject.c | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -750,10 +750,12 @@ if (!PyType_IsSubtype(Py_TYPE(obj), type)) return obj; type = Py_TYPE(obj); - if (type->tp_init != NULL && - type->tp_init(obj, args, kwds) < 0) { - Py_DECREF(obj); - obj = NULL; + if (type->tp_init != NULL) { + int res = type->tp_init(obj, args, kwds); + if (res < 0) { + Py_DECREF(obj); + obj = NULL; + } } } return obj; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 01:01:23 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 01:01:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_typo?= =?utf-8?q?_in_build=5Fnode=5Ftree=28=29_of_the_parser_module?= Message-ID: <3bvxtW3Vpzz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/c8696ee49291 changeset: 84678:c8696ee49291 user: Victor Stinner date: Wed Jul 17 00:13:52 2013 +0200 summary: Issue #18408: Fix typo in build_node_tree() of the parser module Type "o" format of Py_BuildValue() is invalid: it must be "O". files: Modules/parsermodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c --- a/Modules/parsermodule.c +++ b/Modules/parsermodule.c @@ -899,7 +899,7 @@ * The tuple is simple, but it doesn't start with a start symbol. * Raise an exception now and be done with it. */ - tuple = Py_BuildValue("os", tuple, + tuple = Py_BuildValue("Os", tuple, "Illegal syntax-tree; cannot start with terminal symbol."); PyErr_SetObject(parser_error, tuple); Py_XDECREF(tuple); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 01:01:24 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 01:01:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_Pyth?= =?utf-8?q?on-ast=2Ec=3A_handle_init=5Ftypes=28=29_failure_=28ex=3A_Memory?= =?utf-8?q?Error=29?= Message-ID: <3bvxtX5STmz7Lkj@mail.python.org> http://hg.python.org/cpython/rev/cf8f42eadbd0 changeset: 84679:cf8f42eadbd0 user: Victor Stinner date: Wed Jul 17 00:17:15 2013 +0200 summary: Issue #18408: Fix Python-ast.c: handle init_types() failure (ex: MemoryError) files: Parser/asdl_c.py | 9 ++++++--- Python/Python-ast.c | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1191,7 +1191,8 @@ CODE = """ PyObject* PyAST_mod2obj(mod_ty t) { - init_types(); + if (!init_types()) + return NULL; return ast2obj_mod(t); } @@ -1205,7 +1206,8 @@ int isinstance; assert(0 <= mode && mode <= 2); - init_types(); + if (!init_types()) + return NULL; isinstance = PyObject_IsInstance(ast, req_type[mode]); if (isinstance == -1) @@ -1223,7 +1225,8 @@ int PyAST_Check(PyObject* obj) { - init_types(); + if (!init_types()) + return -1; return PyObject_IsInstance(obj, (PyObject*)&AST_type); } """ diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -7188,7 +7188,8 @@ PyObject* PyAST_mod2obj(mod_ty t) { - init_types(); + if (!init_types()) + return NULL; return ast2obj_mod(t); } @@ -7202,7 +7203,8 @@ int isinstance; assert(0 <= mode && mode <= 2); - init_types(); + if (!init_types()) + return NULL; isinstance = PyObject_IsInstance(ast, req_type[mode]); if (isinstance == -1) @@ -7220,7 +7222,8 @@ int PyAST_Check(PyObject* obj) { - init_types(); + if (!init_types()) + return -1; return PyObject_IsInstance(obj, (PyObject*)&AST_type); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 01:01:26 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 01:01:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_PyEr?= =?utf-8?q?r=5FNormalizeException=28=29=2C_handle_PyObject=5FIsSubclass=28?= =?utf-8?q?=29?= Message-ID: <3bvxtZ05CLz7LlR@mail.python.org> http://hg.python.org/cpython/rev/a685f4c6e0b6 changeset: 84680:a685f4c6e0b6 user: Victor Stinner date: Wed Jul 17 00:44:53 2013 +0200 summary: Issue #18408: Fix PyErr_NormalizeException(), handle PyObject_IsSubclass() failure PyObject_IsSubclass() can fail and raise a new exception! files: Python/errors.c | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -227,12 +227,21 @@ value will be an instance. */ if (PyExceptionClass_Check(type)) { + int is_subclass; + if (inclass) { + is_subclass = PyObject_IsSubclass(inclass, type); + if (is_subclass < 0) + goto finally; + } + else + is_subclass = 0; + /* if the value was not an instance, or is not an instance whose class is (or is derived from) type, then use the value as an argument to instantiation of the type class. */ - if (!inclass || !PyObject_IsSubclass(inclass, type)) { + if (!inclass || !is_subclass) { PyObject *args, *res; if (value == Py_None) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 01:01:27 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 01:01:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_loca?= =?utf-8?q?le=2Elocaleconv=28=29=2C_handle_PyDict=5FSetItemString=28=29_fa?= =?utf-8?q?ilure?= Message-ID: <3bvxtb1zfNz7LlR@mail.python.org> http://hg.python.org/cpython/rev/7fe4a0c0e905 changeset: 84681:7fe4a0c0e905 user: Victor Stinner date: Wed Jul 17 00:55:57 2013 +0200 summary: Issue #18408: Fix locale.localeconv(), handle PyDict_SetItemString() failure files: Modules/_localemodule.c | 36 ++++++++++++++++------------ 1 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -147,26 +147,32 @@ /* hopefully, the localeconv result survives the C library calls involved herein */ +#define RESULT(key, obj)\ + do { \ + if (obj == NULL) \ + goto failed; \ + if (PyDict_SetItemString(result, key, obj) < 0) \ + goto failed; \ + Py_DECREF(obj); \ + } while (0) + #define RESULT_STRING(s)\ - x = PyUnicode_DecodeLocale(l->s, NULL); \ - if (!x) goto failed;\ - PyDict_SetItemString(result, #s, x);\ - Py_XDECREF(x) + do { \ + x = PyUnicode_DecodeLocale(l->s, NULL); \ + RESULT(#s, x); \ + } while (0) #define RESULT_INT(i)\ - x = PyLong_FromLong(l->i);\ - if (!x) goto failed;\ - PyDict_SetItemString(result, #i, x);\ - Py_XDECREF(x) + do { \ + x = PyLong_FromLong(l->i); \ + RESULT(#i, x); \ + } while (0) /* Numeric information */ RESULT_STRING(decimal_point); RESULT_STRING(thousands_sep); x = copy_grouping(l->grouping); - if (!x) - goto failed; - PyDict_SetItemString(result, "grouping", x); - Py_XDECREF(x); + RESULT("grouping", x); /* Monetary information */ RESULT_STRING(int_curr_symbol); @@ -174,10 +180,8 @@ RESULT_STRING(mon_decimal_point); RESULT_STRING(mon_thousands_sep); x = copy_grouping(l->mon_grouping); - if (!x) - goto failed; - PyDict_SetItemString(result, "mon_grouping", x); - Py_XDECREF(x); + RESULT("mon_grouping", x); + RESULT_STRING(positive_sign); RESULT_STRING(negative_sign); RESULT_INT(int_frac_digits); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 01:01:28 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 01:01:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Handle_P?= =?utf-8?q?yArena=5FAddPyObject=28=29_failure_in_ast=2Ec?= Message-ID: <3bvxtc3qfNz7LlP@mail.python.org> http://hg.python.org/cpython/rev/8c1ca6720246 changeset: 84682:8c1ca6720246 user: Victor Stinner date: Wed Jul 17 00:57:58 2013 +0200 summary: Issue #18408: Handle PyArena_AddPyObject() failure in ast.c PyList_Append() (called by PyArena_AddPyObject()) can fail because of a MemoryError for example. files: Python/ast.c | 25 ++++++++++++++++++++----- 1 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -560,7 +560,10 @@ id = id2; } PyUnicode_InternInPlace(&id); - PyArena_AddPyObject(c->c_arena, id); + if (PyArena_AddPyObject(c->c_arena, id) < 0) { + Py_DECREF(id); + return NULL; + } return id; } @@ -1847,7 +1850,10 @@ } return NULL; } - PyArena_AddPyObject(c->c_arena, str); + if (PyArena_AddPyObject(c->c_arena, str) < 0) { + Py_DECREF(str); + return NULL; + } if (bytesmode) return Bytes(str, LINENO(n), n->n_col_offset, c->c_arena); else @@ -1858,7 +1864,10 @@ if (!pynum) return NULL; - PyArena_AddPyObject(c->c_arena, pynum); + if (PyArena_AddPyObject(c->c_arena, pynum) < 0) { + Py_DECREF(pynum); + return NULL; + } return Num(pynum, LINENO(n), n->n_col_offset, c->c_arena); } case ELLIPSIS: /* Ellipsis */ @@ -2845,13 +2854,19 @@ return NULL; str = uni; PyUnicode_InternInPlace(&str); - PyArena_AddPyObject(c->c_arena, str); + if (PyArena_AddPyObject(c->c_arena, str) < 0) { + Py_DECREF(str); + return NULL; + } return alias(str, NULL, c->c_arena); } break; case STAR: str = PyUnicode_InternFromString("*"); - PyArena_AddPyObject(c->c_arena, str); + if (PyArena_AddPyObject(c->c_arena, str) < 0) { + Py_DECREF(str); + return NULL; + } return alias(str, NULL, c->c_arena); default: PyErr_Format(PyExc_SystemError, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 01:10:21 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 01:10:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Mention_?= =?utf-8?q?changes_in_Misc/NEWS?= Message-ID: <3bvy4s2dPzz7Ll4@mail.python.org> http://hg.python.org/cpython/rev/1872555a2f4e changeset: 84683:1872555a2f4e user: Victor Stinner date: Wed Jul 17 01:10:04 2013 +0200 summary: Issue #18408: Mention changes in Misc/NEWS files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18408: Fix many various bugs in code handling errors, especially + on memory allocation failure (MemoryError). + - Issue #18344: Fix potential ref-leaks in _bufferedreader_read_all(). - Issue #18342: Use the repr of a module name when an import fails when using -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 01:24:37 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 01:24:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2318469=3A_Replace_?= =?utf-8?q?PyDict=5FGetItemString=28=29_with_=5FPyDict=5FGetItemId=28=29_i?= =?utf-8?q?n?= Message-ID: <3bvyPK31nBz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/af18829a7754 changeset: 84684:af18829a7754 user: Victor Stinner date: Wed Jul 17 01:22:45 2013 +0200 summary: Close #18469: Replace PyDict_GetItemString() with _PyDict_GetItemId() in structseq.c _PyDict_GetItemId() is more efficient: it only builds the Unicode string once. Identifiers (dictionary keys) are now created at Python initialization, and if the creation failed, Python does exit with a fatal error. Before, PyDict_GetItemString() failure was not handled: structseq_new() could call PyObject_GC_NewVar() with a negative size, and structseq_dealloc() could also crash. files: Objects/structseq.c | 25 ++++++++++++++++++++----- Python/pythonrun.c | 3 +++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Objects/structseq.c b/Objects/structseq.c --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -11,17 +11,20 @@ /* Fields with this name have only a field index, not a field name. They are only allowed for indices < n_visible_fields. */ char *PyStructSequence_UnnamedField = "unnamed field"; +_Py_IDENTIFIER(n_sequence_fields); +_Py_IDENTIFIER(n_fields); +_Py_IDENTIFIER(n_unnamed_fields); #define VISIBLE_SIZE(op) Py_SIZE(op) #define VISIBLE_SIZE_TP(tp) PyLong_AsLong( \ - PyDict_GetItemString((tp)->tp_dict, visible_length_key)) + _PyDict_GetItemId((tp)->tp_dict, &PyId_n_sequence_fields)) #define REAL_SIZE_TP(tp) PyLong_AsLong( \ - PyDict_GetItemString((tp)->tp_dict, real_length_key)) + _PyDict_GetItemId((tp)->tp_dict, &PyId_n_fields)) #define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op)) #define UNNAMED_FIELDS_TP(tp) PyLong_AsLong( \ - PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key)) + _PyDict_GetItemId((tp)->tp_dict, &PyId_n_unnamed_fields)) #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op)) @@ -59,7 +62,7 @@ structseq_dealloc(PyStructSequence *obj) { Py_ssize_t i, size; - + size = REAL_SIZE(obj); for (i = 0; i < size; ++i) { Py_XDECREF(obj->ob_item[i]); @@ -382,9 +385,21 @@ PyTypeObject* PyStructSequence_NewType(PyStructSequence_Desc *desc) { - PyTypeObject *result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); + PyTypeObject *result; + + result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); if (result != NULL) { PyStructSequence_InitType(result, desc); } return result; } + +int _PyStructSequence_Init(void) +{ + if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL + || _PyUnicode_FromId(&PyId_n_fields) == NULL + || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL) + return -1; + + return 0; +} diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -86,6 +86,7 @@ static void wait_for_thread_shutdown(void); static void call_ll_exitfuncs(void); extern int _PyUnicode_Init(void); +extern int _PyStructSequence_Init(void); extern void _PyUnicode_Fini(void); extern int _PyLong_Init(void); extern void PyLong_Fini(void); @@ -336,6 +337,8 @@ /* Init Unicode implementation; relies on the codec registry */ if (_PyUnicode_Init() < 0) Py_FatalError("Py_Initialize: can't initialize unicode"); + if (_PyStructSequence_Init() < 0) + Py_FatalError("Py_Initialize: can't initialize structseq"); bimod = _PyBuiltin_Init(); if (bimod == NULL) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Jul 17 05:49:16 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 17 Jul 2013 05:49:16 +0200 Subject: [Python-checkins] Daily reference leaks (af18829a7754): sum=0 Message-ID: results for af18829a7754 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogOgxlAw', '-x'] From python-checkins at python.org Wed Jul 17 12:27:13 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 17 Jul 2013 12:27:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NzY3?= =?utf-8?q?=3A_test=5Flocale_now_works_with_unittest_test_discovery=2E?= Message-ID: <3bwF5s3d6Nz7Ljy@mail.python.org> http://hg.python.org/cpython/rev/3b883491a5f2 changeset: 84685:3b883491a5f2 branch: 3.3 parent: 84667:6e8ad6071100 user: Serhiy Storchaka date: Wed Jul 17 13:23:45 2013 +0300 summary: Issue #17767: test_locale now works with unittest test discovery. Original patch by Zachary Ware. files: Lib/test/test_locale.py | 94 +++++++++++----------------- Misc/NEWS | 3 + 2 files changed, 39 insertions(+), 58 deletions(-) diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -1,52 +1,50 @@ -from test.support import run_unittest, verbose +from test.support import verbose import unittest import locale import sys import codecs -enUS_locale = None - -def get_enUS_locale(): - global enUS_locale - if sys.platform == 'darwin': - import os - tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US") - if int(os.uname().release.split('.')[0]) < 10: - # The locale test work fine on OSX 10.6, I (ronaldoussoren) - # haven't had time yet to verify if tests work on OSX 10.5 - # (10.4 is known to be bad) - raise unittest.SkipTest("Locale support on MacOSX is minimal") - elif sys.platform.startswith("win"): - tlocs = ("En", "English") - else: - tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US.US-ASCII", "en_US") - oldlocale = locale.setlocale(locale.LC_NUMERIC) - for tloc in tlocs: - try: - locale.setlocale(locale.LC_NUMERIC, tloc) - except locale.Error: - continue - break - else: - raise unittest.SkipTest( - "Test locale not supported (tried %s)" % (', '.join(tlocs))) - enUS_locale = tloc - locale.setlocale(locale.LC_NUMERIC, oldlocale) - - class BaseLocalizedTest(unittest.TestCase): # # Base class for tests using a real locale # + @classmethod + def setUpClass(cls): + if sys.platform == 'darwin': + import os + tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US") + if int(os.uname().release.split('.')[0]) < 10: + # The locale test work fine on OSX 10.6, I (ronaldoussoren) + # haven't had time yet to verify if tests work on OSX 10.5 + # (10.4 is known to be bad) + raise unittest.SkipTest("Locale support on MacOSX is minimal") + elif sys.platform.startswith("win"): + tlocs = ("En", "English") + else: + tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", + "en_US.US-ASCII", "en_US") + try: + oldlocale = locale.setlocale(locale.LC_NUMERIC) + for tloc in tlocs: + try: + locale.setlocale(locale.LC_NUMERIC, tloc) + except locale.Error: + continue + break + else: + raise unittest.SkipTest("Test locale not supported " + "(tried %s)" % (', '.join(tlocs))) + cls.enUS_locale = tloc + finally: + locale.setlocale(locale.LC_NUMERIC, oldlocale) + def setUp(self): - self.oldlocale = locale.setlocale(self.locale_type) - locale.setlocale(self.locale_type, enUS_locale) + oldlocale = locale.setlocale(self.locale_type) + self.addCleanup(locale.setlocale, self.locale_type, oldlocale) + locale.setlocale(self.locale_type, self.enUS_locale) if verbose: - print("testing with \"%s\"..." % enUS_locale, end=' ') - - def tearDown(self): - locale.setlocale(self.locale_type, self.oldlocale) + print("testing with %r..." % self.enUS_locale, end=' ', flush=True) class BaseCookedTest(unittest.TestCase): @@ -415,25 +413,5 @@ locale.setlocale(locale.LC_ALL, (b'not', b'valid')) -def test_main(): - tests = [ - TestMiscellaneous, - TestFormatPatternArg, - TestLocaleFormatString, - TestEnUSNumberFormatting, - TestCNumberFormatting, - TestFrFRNumberFormatting, - TestCollation - ] - # SkipTest can't be raised inside unittests, handle it manually instead - try: - get_enUS_locale() - except unittest.SkipTest as e: - if verbose: - print("Some tests will be disabled: %s" % e) - else: - tests += [TestNumberFormatting, TestEnUSCollation] - run_unittest(*tests) - if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -198,6 +198,9 @@ Tests ----- +- Issue #17767: test_locale now works with unittest test discovery. + Original patch by Zachary Ware. + - Issue #18375: Assume --randomize when --randseed is used for running the testsuite. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 12:27:14 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 17 Jul 2013 12:27:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317767=3A_test=5Flocale_now_works_with_unittest_?= =?utf-8?q?test_discovery=2E?= Message-ID: <3bwF5t6tTJz7Lll@mail.python.org> http://hg.python.org/cpython/rev/60e72210683c changeset: 84686:60e72210683c parent: 84684:af18829a7754 parent: 84685:3b883491a5f2 user: Serhiy Storchaka date: Wed Jul 17 13:26:48 2013 +0300 summary: Issue #17767: test_locale now works with unittest test discovery. Original patch by Zachary Ware. files: Lib/test/test_locale.py | 94 +++++++++++----------------- Misc/NEWS | 3 + 2 files changed, 39 insertions(+), 58 deletions(-) diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -1,52 +1,50 @@ -from test.support import run_unittest, verbose +from test.support import verbose import unittest import locale import sys import codecs -enUS_locale = None - -def get_enUS_locale(): - global enUS_locale - if sys.platform == 'darwin': - import os - tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US") - if int(os.uname().release.split('.')[0]) < 10: - # The locale test work fine on OSX 10.6, I (ronaldoussoren) - # haven't had time yet to verify if tests work on OSX 10.5 - # (10.4 is known to be bad) - raise unittest.SkipTest("Locale support on MacOSX is minimal") - elif sys.platform.startswith("win"): - tlocs = ("En", "English") - else: - tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US.US-ASCII", "en_US") - oldlocale = locale.setlocale(locale.LC_NUMERIC) - for tloc in tlocs: - try: - locale.setlocale(locale.LC_NUMERIC, tloc) - except locale.Error: - continue - break - else: - raise unittest.SkipTest( - "Test locale not supported (tried %s)" % (', '.join(tlocs))) - enUS_locale = tloc - locale.setlocale(locale.LC_NUMERIC, oldlocale) - - class BaseLocalizedTest(unittest.TestCase): # # Base class for tests using a real locale # + @classmethod + def setUpClass(cls): + if sys.platform == 'darwin': + import os + tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", "en_US") + if int(os.uname().release.split('.')[0]) < 10: + # The locale test work fine on OSX 10.6, I (ronaldoussoren) + # haven't had time yet to verify if tests work on OSX 10.5 + # (10.4 is known to be bad) + raise unittest.SkipTest("Locale support on MacOSX is minimal") + elif sys.platform.startswith("win"): + tlocs = ("En", "English") + else: + tlocs = ("en_US.UTF-8", "en_US.ISO8859-1", + "en_US.US-ASCII", "en_US") + try: + oldlocale = locale.setlocale(locale.LC_NUMERIC) + for tloc in tlocs: + try: + locale.setlocale(locale.LC_NUMERIC, tloc) + except locale.Error: + continue + break + else: + raise unittest.SkipTest("Test locale not supported " + "(tried %s)" % (', '.join(tlocs))) + cls.enUS_locale = tloc + finally: + locale.setlocale(locale.LC_NUMERIC, oldlocale) + def setUp(self): - self.oldlocale = locale.setlocale(self.locale_type) - locale.setlocale(self.locale_type, enUS_locale) + oldlocale = locale.setlocale(self.locale_type) + self.addCleanup(locale.setlocale, self.locale_type, oldlocale) + locale.setlocale(self.locale_type, self.enUS_locale) if verbose: - print("testing with \"%s\"..." % enUS_locale, end=' ') - - def tearDown(self): - locale.setlocale(self.locale_type, self.oldlocale) + print("testing with %r..." % self.enUS_locale, end=' ', flush=True) class BaseCookedTest(unittest.TestCase): @@ -415,25 +413,5 @@ locale.setlocale(locale.LC_ALL, (b'not', b'valid')) -def test_main(): - tests = [ - TestMiscellaneous, - TestFormatPatternArg, - TestLocaleFormatString, - TestEnUSNumberFormatting, - TestCNumberFormatting, - TestFrFRNumberFormatting, - TestCollation - ] - # SkipTest can't be raised inside unittests, handle it manually instead - try: - get_enUS_locale() - except unittest.SkipTest as e: - if verbose: - print("Some tests will be disabled: %s" % e) - else: - tests += [TestNumberFormatting, TestEnUSCollation] - run_unittest(*tests) - if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -529,6 +529,9 @@ Tests ----- +- Issue #17767: test_locale now works with unittest test discovery. + Original patch by Zachary Ware. + - Issue #18375: Assume --randomize when --randseed is used for running the testsuite. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 12:44:41 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 17 Jul 2013 12:44:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MjY2?= =?utf-8?q?=3A_test=5Flargefile_now_works_with_unittest_test_discovery_and?= Message-ID: <3bwFV14H86z7LjW@mail.python.org> http://hg.python.org/cpython/rev/dd75dbed1135 changeset: 84687:dd75dbed1135 branch: 3.3 parent: 84685:3b883491a5f2 user: Serhiy Storchaka date: Wed Jul 17 13:42:24 2013 +0300 summary: Issue #18266: test_largefile now works with unittest test discovery and supports running only selected tests. Patch by Zachary Ware. files: Lib/test/test_largefile.py | 118 +++++++++++------------- Misc/NEWS | 3 + 2 files changed, 56 insertions(+), 65 deletions(-) diff --git a/Lib/test/test_largefile.py b/Lib/test/test_largefile.py --- a/Lib/test/test_largefile.py +++ b/Lib/test/test_largefile.py @@ -5,55 +5,50 @@ import stat import sys import unittest -from test.support import run_unittest, TESTFN, verbose, requires, \ - unlink +from test.support import TESTFN, requires, unlink import io # C implementation of io import _pyio as pyio # Python implementation of io -try: - import signal - # The default handler for SIGXFSZ is to abort the process. - # By ignoring it, system calls exceeding the file size resource - # limit will raise IOError instead of crashing the interpreter. - oldhandler = signal.signal(signal.SIGXFSZ, signal.SIG_IGN) -except (ImportError, AttributeError): - pass - -# create >2GB file (2GB = 2147483648 bytes) +# size of file to create (>2GB; 2GB == 2147483648 bytes) size = 2500000000 - -class LargeFileTest(unittest.TestCase): - """Test that each file function works as expected for a large - (i.e. > 2GB, do we have to check > 4GB) files. - - NOTE: the order of execution of the test methods is important! test_seek - must run first to create the test file. File cleanup must also be handled - outside the test instances because of this. - +class LargeFileTest: + """Test that each file function works as expected for large + (i.e. > 2GB) files. """ - def test_seek(self): - if verbose: - print('create large file via seek (may be sparse file) ...') - with self.open(TESTFN, 'wb') as f: - f.write(b'z') + def setUp(self): + if os.path.exists(TESTFN): + mode = 'r+b' + else: + mode = 'w+b' + + with self.open(TESTFN, mode) as f: + current_size = os.fstat(f.fileno())[stat.ST_SIZE] + if current_size == size+1: + return + + if current_size == 0: + f.write(b'z') + f.seek(0) f.seek(size) f.write(b'a') f.flush() - if verbose: - print('check file size with os.fstat') self.assertEqual(os.fstat(f.fileno())[stat.ST_SIZE], size+1) + @classmethod + def tearDownClass(cls): + with cls.open(TESTFN, 'wb'): + pass + if not os.stat(TESTFN)[stat.ST_SIZE] == 0: + raise cls.failureException('File was not truncated by opening ' + 'with mode "wb"') + def test_osstat(self): - if verbose: - print('check file size with os.stat') self.assertEqual(os.stat(TESTFN)[stat.ST_SIZE], size+1) def test_seek_read(self): - if verbose: - print('play around with seek() and read() with the built largefile') with self.open(TESTFN, 'rb') as f: self.assertEqual(f.tell(), 0) self.assertEqual(f.read(1), b'z') @@ -85,8 +80,6 @@ self.assertEqual(f.tell(), 1) def test_lseek(self): - if verbose: - print('play around with os.lseek() with the built largefile') with self.open(TESTFN, 'rb') as f: self.assertEqual(os.lseek(f.fileno(), 0, 0), 0) self.assertEqual(os.lseek(f.fileno(), 42, 0), 42) @@ -100,13 +93,10 @@ self.assertEqual(f.read(1), b'a') def test_truncate(self): - if verbose: - print('try truncate') with self.open(TESTFN, 'r+b') as f: - # this is already decided before start running the test suite - # but we do it anyway for extra protection if not hasattr(f, 'truncate'): - raise unittest.SkipTest("open().truncate() not available on this system") + raise unittest.SkipTest("open().truncate() not available " + "on this system") f.seek(0, 2) # else we've lost track of the true size self.assertEqual(f.tell(), size+1) @@ -141,8 +131,16 @@ f.seek(pos) self.assertTrue(f.seekable()) +def setUpModule(): + try: + import signal + # The default handler for SIGXFSZ is to abort the process. + # By ignoring it, system calls exceeding the file size resource + # limit will raise OSError instead of crashing the interpreter. + signal.signal(signal.SIGXFSZ, signal.SIG_IGN) + except (ImportError, AttributeError): + pass -def test_main(): # On Windows and Mac OSX this test comsumes large resources; It # takes a long time to build the >2GB file and takes >2GB of disk # space therefore the resource must be enabled to run this test. @@ -158,35 +156,25 @@ try: # 2**31 == 2147483648 f.seek(2147483649) - # Seeking is not enough of a test: you must write and - # flush, too! + # Seeking is not enough of a test: you must write and flush, too! f.write(b'x') f.flush() except (IOError, OverflowError): + raise unittest.SkipTest("filesystem does not have " + "largefile support") + finally: f.close() unlink(TESTFN) - raise unittest.SkipTest("filesystem does not have largefile support") - else: - f.close() - suite = unittest.TestSuite() - for _open, prefix in [(io.open, 'C'), (pyio.open, 'Py')]: - class TestCase(LargeFileTest): - pass - TestCase.open = staticmethod(_open) - TestCase.__name__ = prefix + LargeFileTest.__name__ - suite.addTest(TestCase('test_seek')) - suite.addTest(TestCase('test_osstat')) - suite.addTest(TestCase('test_seek_read')) - suite.addTest(TestCase('test_lseek')) - with _open(TESTFN, 'wb') as f: - if hasattr(f, 'truncate'): - suite.addTest(TestCase('test_truncate')) - suite.addTest(TestCase('test_seekable')) - unlink(TESTFN) - try: - run_unittest(suite) - finally: - unlink(TESTFN) + + +class CLargeFileTest(LargeFileTest, unittest.TestCase): + open = staticmethod(io.open) + +class PyLargeFileTest(LargeFileTest, unittest.TestCase): + open = staticmethod(pyio.open) + +def tearDownModule(): + unlink(TESTFN) if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -198,6 +198,9 @@ Tests ----- +- Issue #18266: test_largefile now works with unittest test discovery and + supports running only selected tests. Patch by Zachary Ware. + - Issue #17767: test_locale now works with unittest test discovery. Original patch by Zachary Ware. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 12:44:43 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 17 Jul 2013 12:44:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318266=3A_test=5Flargefile_now_works_with_unitte?= =?utf-8?q?st_test_discovery_and?= Message-ID: <3bwFV30Hbqz7LkJ@mail.python.org> http://hg.python.org/cpython/rev/2d8573e12591 changeset: 84688:2d8573e12591 parent: 84686:60e72210683c parent: 84687:dd75dbed1135 user: Serhiy Storchaka date: Wed Jul 17 13:44:17 2013 +0300 summary: Issue #18266: test_largefile now works with unittest test discovery and supports running only selected tests. Patch by Zachary Ware. files: Lib/test/test_largefile.py | 118 +++++++++++------------- Misc/NEWS | 3 + 2 files changed, 56 insertions(+), 65 deletions(-) diff --git a/Lib/test/test_largefile.py b/Lib/test/test_largefile.py --- a/Lib/test/test_largefile.py +++ b/Lib/test/test_largefile.py @@ -5,55 +5,50 @@ import stat import sys import unittest -from test.support import run_unittest, TESTFN, verbose, requires, \ - unlink +from test.support import TESTFN, requires, unlink import io # C implementation of io import _pyio as pyio # Python implementation of io -try: - import signal - # The default handler for SIGXFSZ is to abort the process. - # By ignoring it, system calls exceeding the file size resource - # limit will raise OSError instead of crashing the interpreter. - oldhandler = signal.signal(signal.SIGXFSZ, signal.SIG_IGN) -except (ImportError, AttributeError): - pass - -# create >2GB file (2GB = 2147483648 bytes) +# size of file to create (>2GB; 2GB == 2147483648 bytes) size = 2500000000 - -class LargeFileTest(unittest.TestCase): - """Test that each file function works as expected for a large - (i.e. > 2GB, do we have to check > 4GB) files. - - NOTE: the order of execution of the test methods is important! test_seek - must run first to create the test file. File cleanup must also be handled - outside the test instances because of this. - +class LargeFileTest: + """Test that each file function works as expected for large + (i.e. > 2GB) files. """ - def test_seek(self): - if verbose: - print('create large file via seek (may be sparse file) ...') - with self.open(TESTFN, 'wb') as f: - f.write(b'z') + def setUp(self): + if os.path.exists(TESTFN): + mode = 'r+b' + else: + mode = 'w+b' + + with self.open(TESTFN, mode) as f: + current_size = os.fstat(f.fileno())[stat.ST_SIZE] + if current_size == size+1: + return + + if current_size == 0: + f.write(b'z') + f.seek(0) f.seek(size) f.write(b'a') f.flush() - if verbose: - print('check file size with os.fstat') self.assertEqual(os.fstat(f.fileno())[stat.ST_SIZE], size+1) + @classmethod + def tearDownClass(cls): + with cls.open(TESTFN, 'wb'): + pass + if not os.stat(TESTFN)[stat.ST_SIZE] == 0: + raise cls.failureException('File was not truncated by opening ' + 'with mode "wb"') + def test_osstat(self): - if verbose: - print('check file size with os.stat') self.assertEqual(os.stat(TESTFN)[stat.ST_SIZE], size+1) def test_seek_read(self): - if verbose: - print('play around with seek() and read() with the built largefile') with self.open(TESTFN, 'rb') as f: self.assertEqual(f.tell(), 0) self.assertEqual(f.read(1), b'z') @@ -85,8 +80,6 @@ self.assertEqual(f.tell(), 1) def test_lseek(self): - if verbose: - print('play around with os.lseek() with the built largefile') with self.open(TESTFN, 'rb') as f: self.assertEqual(os.lseek(f.fileno(), 0, 0), 0) self.assertEqual(os.lseek(f.fileno(), 42, 0), 42) @@ -100,13 +93,10 @@ self.assertEqual(f.read(1), b'a') def test_truncate(self): - if verbose: - print('try truncate') with self.open(TESTFN, 'r+b') as f: - # this is already decided before start running the test suite - # but we do it anyway for extra protection if not hasattr(f, 'truncate'): - raise unittest.SkipTest("open().truncate() not available on this system") + raise unittest.SkipTest("open().truncate() not available " + "on this system") f.seek(0, 2) # else we've lost track of the true size self.assertEqual(f.tell(), size+1) @@ -141,8 +131,16 @@ f.seek(pos) self.assertTrue(f.seekable()) +def setUpModule(): + try: + import signal + # The default handler for SIGXFSZ is to abort the process. + # By ignoring it, system calls exceeding the file size resource + # limit will raise OSError instead of crashing the interpreter. + signal.signal(signal.SIGXFSZ, signal.SIG_IGN) + except (ImportError, AttributeError): + pass -def test_main(): # On Windows and Mac OSX this test comsumes large resources; It # takes a long time to build the >2GB file and takes >2GB of disk # space therefore the resource must be enabled to run this test. @@ -158,35 +156,25 @@ try: # 2**31 == 2147483648 f.seek(2147483649) - # Seeking is not enough of a test: you must write and - # flush, too! + # Seeking is not enough of a test: you must write and flush, too! f.write(b'x') f.flush() except (OSError, OverflowError): + raise unittest.SkipTest("filesystem does not have " + "largefile support") + finally: f.close() unlink(TESTFN) - raise unittest.SkipTest("filesystem does not have largefile support") - else: - f.close() - suite = unittest.TestSuite() - for _open, prefix in [(io.open, 'C'), (pyio.open, 'Py')]: - class TestCase(LargeFileTest): - pass - TestCase.open = staticmethod(_open) - TestCase.__name__ = prefix + LargeFileTest.__name__ - suite.addTest(TestCase('test_seek')) - suite.addTest(TestCase('test_osstat')) - suite.addTest(TestCase('test_seek_read')) - suite.addTest(TestCase('test_lseek')) - with _open(TESTFN, 'wb') as f: - if hasattr(f, 'truncate'): - suite.addTest(TestCase('test_truncate')) - suite.addTest(TestCase('test_seekable')) - unlink(TESTFN) - try: - run_unittest(suite) - finally: - unlink(TESTFN) + + +class CLargeFileTest(LargeFileTest, unittest.TestCase): + open = staticmethod(io.open) + +class PyLargeFileTest(LargeFileTest, unittest.TestCase): + open = staticmethod(pyio.open) + +def tearDownModule(): + unlink(TESTFN) if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -529,6 +529,9 @@ Tests ----- +- Issue #18266: test_largefile now works with unittest test discovery and + supports running only selected tests. Patch by Zachary Ware. + - Issue #17767: test_locale now works with unittest test discovery. Original patch by Zachary Ware. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 13:15:24 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 13:15:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_446=3A_On_Windows=2C_the_?= =?utf-8?q?close-on-exec_flag_is_the_*inverse*_of?= Message-ID: <3bwG9S1frzz7Ll5@mail.python.org> http://hg.python.org/peps/rev/4f1e1692c573 changeset: 5002:4f1e1692c573 user: Victor Stinner date: Wed Jul 17 12:48:58 2013 +0200 summary: PEP 446: On Windows, the close-on-exec flag is the *inverse* of HANDLE_FLAG_INHERIT files: pep-0446.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -27,7 +27,7 @@ on each file descriptor using a *close-on-exec* flag. By default, the close-on-exec flag is not set. -On Windows, the close-on-exec flag is ``HANDLE_FLAG_INHERIT``. File +On Windows, the close-on-exec flag is the inverse of ``HANDLE_FLAG_INHERIT``. File descriptors are not inherited if the ``bInheritHandles`` parameter of the ``CreateProcess()`` function is ``FALSE``, even if the ``HANDLE_FLAG_INHERIT`` flag is set. If ``bInheritHandles`` is ``TRUE``, @@ -149,7 +149,7 @@ The ``subprocess.Popen`` class must clear the close-on-exec flag of file descriptors of the ``pass_fds`` parameter. The flag is cleared in the -child process before executing the program, the change does not change +child process before executing the program; the change does not change the flag in the parent process. The close-on-exec flag must also be set on private file descriptors and -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jul 17 13:15:25 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 13:15:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_466=3A_add_test=5Fcloexec?= =?utf-8?b?LnB5?= Message-ID: <3bwG9T3DD3z7LmH@mail.python.org> http://hg.python.org/peps/rev/464590583890 changeset: 5003:464590583890 user: Victor Stinner date: Wed Jul 17 13:10:26 2013 +0200 summary: PEP 466: add test_cloexec.py files: pep-0466/test_cloexec.py | 50 ++++++++++++++++++++++++++++ 1 files changed, 50 insertions(+), 0 deletions(-) diff --git a/pep-0466/test_cloexec.py b/pep-0466/test_cloexec.py new file mode 100644 --- /dev/null +++ b/pep-0466/test_cloexec.py @@ -0,0 +1,50 @@ +import os, fcntl, sys, errno + +def get_cloexec(fd): + try: + flags = fcntl.fcntl(fd, fcntl.F_GETFD) + return bool(flags & fcntl.FD_CLOEXEC) + except IOError as err: + if err.errno == errno.EBADF: + return '' + else: + return str(err) + +def set_cloexec(fd): + flags = fcntl.fcntl(fd, fcntl.F_GETFD) + flags |= fcntl.FD_CLOEXEC + fcntl.fcntl(fd, fcntl.F_SETFD, flags) + +def main(): + f = open(__file__, "rb") + fd = f.fileno() + print("initial state: fd=%s, cloexec=%s" % (fd, get_cloexec(fd))) + + + pid = os.fork() + if not pid: + set_cloexec(fd) + print("child process after fork, set cloexec: cloexec=%s" % get_cloexec(fd)) + child_argv = [sys.executable, __file__, str(fd), + 'child process after exec'] + os.execv(child_argv[0], child_argv) + + os.waitpid(pid, 0) + print("parent process after fork: cloexec=%s" % get_cloexec(fd)) + child_argv = [sys.executable, __file__, str(fd), + 'parent process after exec'] + os.execv(child_argv[0], child_argv) + +def after_exec(): + fd = int(sys.argv[1]) + name = sys.argv[2] + print("%s: fd=%s, cloexec=%s" + % (name, fd, get_cloexec(fd))) + sys.exit() + +if __name__ == "__main__": + if len(sys.argv) == 1: + main() + else: + after_exec() + -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jul 17 13:15:26 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 13:15:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_466=3A_another_counter-ar?= =?utf-8?q?gument_for_open=28blocking=3DTrue=29?= Message-ID: <3bwG9V4tKcz7LmM@mail.python.org> http://hg.python.org/peps/rev/fa873d5aed27 changeset: 5004:fa873d5aed27 user: Victor Stinner date: Wed Jul 17 13:15:18 2013 +0200 summary: PEP 466: another counter-argument for open(blocking=True) files: pep-0446.txt | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -199,6 +199,12 @@ function should not be available on the platform. For example, the ``os.fork()`` function is not available on Windows. +UNIX has more flag on file descriptors: ``O_DSYNC``, ``O_SYNC``, +``O_DIRECT``, etc. Adding all these flags complicates the signature and +the implementation of functions creating file descriptor like open(). +Moreover, these flags do not work on any file type, and are not +portable. + For all these reasons, this alternative was rejected. The PEP 3156 proposes an abstraction for asynchronous I/O supporting non-blocking files on Windows. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jul 17 13:43:34 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 13:43:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_stru?= =?utf-8?q?ctseq=5Freduce=28=29=2C_handle_PyDict=5FSetItemString=28=29_fai?= =?utf-8?q?lure?= Message-ID: <3bwGny2jbbz7LlF@mail.python.org> http://hg.python.org/cpython/rev/7b81a535ad14 changeset: 84689:7b81a535ad14 user: Victor Stinner date: Wed Jul 17 13:41:39 2013 +0200 summary: Issue #18408: Fix structseq_reduce(), handle PyDict_SetItemString() failure files: Objects/structseq.c | 24 +++++++++++++----------- 1 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Objects/structseq.c b/Objects/structseq.c --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -233,8 +233,8 @@ static PyObject * structseq_reduce(PyStructSequence* self) { - PyObject* tup; - PyObject* dict; + PyObject* tup = NULL; + PyObject* dict = NULL; PyObject* result; Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields; int i; @@ -243,15 +243,12 @@ n_visible_fields = VISIBLE_SIZE(self); n_unnamed_fields = UNNAMED_FIELDS(self); tup = PyTuple_New(n_visible_fields); - if (!tup) { - return NULL; - } + if (!tup) + goto error; dict = PyDict_New(); - if (!dict) { - Py_DECREF(tup); - return NULL; - } + if (!dict) + goto error; for (i = 0; i < n_visible_fields; i++) { Py_INCREF(self->ob_item[i]); @@ -260,8 +257,8 @@ for (; i < n_fields; i++) { char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name; - PyDict_SetItemString(dict, n, - self->ob_item[i]); + if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0) + goto error; } result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict); @@ -270,6 +267,11 @@ Py_DECREF(dict); return result; + +error: + Py_XDECREF(tup); + Py_XDECREF(dict); + return NULL; } static PyMethodDef structseq_methods[] = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 16:58:03 2013 From: python-checkins at python.org (ronald.oussoren) Date: Wed, 17 Jul 2013 16:58:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_447_updates?= Message-ID: <3bwM6M1NXqzSqp@mail.python.org> http://hg.python.org/peps/rev/629dc68d03ad changeset: 5005:629dc68d03ad user: Ronald Oussoren date: Wed Jul 17 16:57:39 2013 +0200 summary: PEP 447 updates * Title better reflects what's proposed * Try to clarify the proposal (by changing the text and adding examples) * Add background information on why I'm working on this proposal * Slight semantic change: "type" does not provide a __locallookup__ method. This was done to ensure that the type attribute cache can be kept. files: pep-0447.txt | 128 +++++++++++++++++++++++--------------- 1 files changed, 76 insertions(+), 52 deletions(-) diff --git a/pep-0447.txt b/pep-0447.txt --- a/pep-0447.txt +++ b/pep-0447.txt @@ -1,5 +1,5 @@ PEP: 447 -Title: Hooking into super attribute resolution +Title: Add __locallookup__ method to metaclass Version: $Revision$ Last-Modified: $Date$ Author: Ronald Oussoren @@ -13,21 +13,39 @@ Abstract ======== -In current python releases the attribute resolution of the `super class`_ -peeks in the ``__dict__`` attribute of classes on the MRO to look -for attributes. This PEP introduces a hook that classes can use -to override that behavior for specific classes. - +Currently ``object.__getattribute__`` and ``super.__getattribute__`` peek +in the ``__dict__`` of classes on the MRO for a class when looking for +an attribute. This PEP adds an optional ``__locallookup__`` method to +a metaclass that can be used to override this behavior. Rationale ========= -Peeking in the class ``__dict__`` works for regular classes, but can -cause problems when a class dynamically looks up attributes in a -``__getattribute__`` method. +It is currently not possible to influence how the `super class`_ looks +up attributes (that is, ``super.__getattribute__`` unconditionally +peeks in the class ``__dict__``), and that can be problematic for +dynamic classes that can grow new methods on demand. -This new hook makes it possible to affect attribute lookup for both normal -attribute lookup and lookup through the `super class`_. +The ``__locallookup__`` method makes it possible to dynamicly add +attributes even when looking them up using the `super class`_. + +The new method affects ``object.__getattribute__`` (and +`PyObject_GenericGetAttr`_) as well for consistency. + +Background +---------- + +The current behavior of ``super.__getattribute__`` causes problems for +classes that are dynamic proxies for other (non-Python) classes or types, +an example of which is `PyObjC`_. PyObjC creates a Python class for every +class in the Objective-C runtime, and looks up methods in the Objective-C +runtime when they are used. This works fine for normal access, but doesn't +work for access with ``super`` objects. Because of this PyObjC currently +includes a custom ``super`` that must be used with its classes. + +The API in this PEP makes it possible to remove the custom ``super`` and +simplifies the implementation because the custom lookup behavior can be +added in a central location. The superclass attribute lookup hook @@ -53,14 +71,34 @@ except KeyError: raise AttributeError(name) from None -The example method above is pseudocode for the implementation of this method on -`type`_ (the actual implementation is in C, and doesn't suffer from the recursion -problem in this example). - The ``__locallookup__`` method has as its arguments a class and the name of the attribute that is looked up. It should return the value of the attribute without invoking descriptors, or raise `AttributeError`_ when the name cannot be found. +The `type`_ class does not provide an implementation for ``__locallookup__``, primarily +to enable some optimizations in the Python implementation. + +Example usage +............. + +The code below implements a silly metaclass that redirects attribute lookup to uppercase +versions of names:: + + class UpperCaseAccess (type): + + def __locallookup__(cls, name): + return cls.__dict__[name.upper()] + + class SillyObject (metaclass=UpperCaseAccess): + def m(self): + return 42 + + def M(self): + return "fourtytwo" + + obj = SillyObject() + assert obj.m() == "fortytwo" + In C code --------- @@ -80,23 +118,27 @@ Usage of this hook ------------------ -The new method will be defined for `type`_, and will peek in the class dictionary:: +The new method is optional and will not be defined on `type`_. Both ``super.__getattribute__`` +and ``object.__getattribute__``/`PyObject_GenericGetAttr`_ (through ``_PyType_Lookup``) will use the +the ``__locallookup__`` method when it is present in the meta type of a type on the MRO and will +continue to peek in the type's ``__dict__`` when the meta type does not have a ``__locallookup`` +method. - static PyObject* - type_locallookup(PyTypeObject* cls, PyObject* name) - { - PyObject* res; - if (!cls->tp_dict) { - return NULL; - } +Other changes to the implementation +................................... - res = PyDict_GetItem(cls, name); - Py_XINCREF(res); - return res; - } +The change for `PyObject_GenericGetAttr`_ will be done by changing the private function +``_PyType_Lookup``. This currently returns a borrowed reference, but must return a new +reference when the ``__locallookup__`` method is present. Because of this ``_PyType_Lookup`` +will be renamed to ``_PyType_LookupName``, this will cause compile-time errors for all out-of-tree +users of this private API. -The new method will be used by both `PyObject_GenericGetAttr`_ and -``super.__getattribute__`` instead of peeking in a type's ``tp_dict``. +By making ``__locallookup_`` optional the implementation can continue to use the type attribute +lookup cache for types that don't have a metaclass with this new method, which should minimize the +performance impact of the change. + +**TODO**: run pybench, an possibly the full speedtest, with and without this change and insert +the results. Alternative proposals @@ -127,32 +169,10 @@ dictionaries changes the semantics of the `super class`_. -Open Issues -=========== - -* The names of the new slot and magic method are far from settled. - -* Should the python method raise an exception or return a magic value (such as the - `NotImplemented`_ return value used by comparison operators). The latter could be - slightly faster because it doesn't have to overhead of setting up exception state, but - makes it impossible to use that value as an attribute on a class. - -* The proposed change to `PyObject_GenericGetAttr`_ will probably cause problems with the - attribute lookup cache (MCACHE): - - 1. That code stores borrowed references, which won't work when the hook is present. That - is mostly fixable, but at the cost of possibly keeping garbage alive. - - 2. Caching isn't an option when a hook might execute arbitrary code (and there hence is - no reason to assume that the hooks return value won't change later on). - - The only workaround I could find for this is to make the hook a fallback (that is, - more like ``__getattr__`` than ``__getattribute__``). - References ========== -* `Issue 18181`_ contains a partial prototype implementation +* `Issue 18181`_ contains a prototype implementation Copyright @@ -171,3 +191,7 @@ .. _`type`: http://docs.python.org/3/library/functions.html#type .. _`AttributeError`: http://docs.python.org/3/library/exceptions.html#AttributeError + +.. _`PyObjC`: http://pyobjc.sourceforge.net/ + +.. _`classmethod`: http://docs.python.org/3/library/functions.html#classmethod -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jul 17 22:11:49 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:11:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_time?= =?utf-8?q?=2Etzset=28=29=2C_detect_exception_when_calling_PyInit=5Ftimezo?= =?utf-8?q?ne=28=29?= Message-ID: <3bwV4P42kFz7LkN@mail.python.org> http://hg.python.org/cpython/rev/4d3bb9763bf9 changeset: 84690:4d3bb9763bf9 user: Victor Stinner date: Wed Jul 17 21:42:45 2013 +0200 summary: Issue #18408: Fix time.tzset(), detect exception when calling PyInit_timezone() files: Modules/timemodule.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -851,6 +851,8 @@ /* Reset timezone, altzone, daylight and tzname */ PyInit_timezone(m); Py_DECREF(m); + if (PyErr_Occurred()) + return NULL; Py_INCREF(Py_None); return Py_None; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 22:11:50 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:11:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_heap?= =?utf-8?q?q=2Eheappop=28=29=2C_handle_PyList=5FSetSlice=28=29_failure?= Message-ID: <3bwV4Q5xl5z7LkV@mail.python.org> http://hg.python.org/cpython/rev/563b27bef79f changeset: 84691:563b27bef79f user: Victor Stinner date: Wed Jul 17 21:50:21 2013 +0200 summary: Issue #18408: Fix heapq.heappop(), handle PyList_SetSlice() failure files: Modules/_heapqmodule.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c --- a/Modules/_heapqmodule.c +++ b/Modules/_heapqmodule.c @@ -168,7 +168,10 @@ lastelt = PyList_GET_ITEM(heap, n-1) ; Py_INCREF(lastelt); - PyList_SetSlice(heap, n-1, n, NULL); + if (PyList_SetSlice(heap, n-1, n, NULL) < 0) { + Py_DECREF(lastelt); + return NULL; + } n--; if (!n) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 22:11:52 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:11:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_ast?= =?utf-8?b?X2Zvcl9hdG9tKCksIFB5RXJyX0ZldGNoKCZ0eXBlLCAmdmFsdWUsICZ0YmFj?= =?utf-8?q?k=29_can_set?= Message-ID: <3bwV4S0nWdz7LkT@mail.python.org> http://hg.python.org/cpython/rev/6fb3414710ab changeset: 84692:6fb3414710ab user: Victor Stinner date: Wed Jul 17 21:51:42 2013 +0200 summary: Issue #18408: Fix ast_for_atom(), PyErr_Fetch(&type, &value, &tback) can set value to NULL files: Python/ast.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -1845,7 +1845,7 @@ } ast_error(c, n, buf); Py_DECREF(type); - Py_DECREF(value); + Py_XDECREF(value); Py_XDECREF(tback); } return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 22:11:53 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:11:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_=5FP?= =?utf-8?q?yImport=5FLoadDynamicModule=28=29=2C_handle_PyUnicode=5FFromFor?= =?utf-8?b?bWF0KCk=?= Message-ID: <3bwV4T2x6lz7Ll1@mail.python.org> http://hg.python.org/cpython/rev/479af6ca3a3c changeset: 84693:479af6ca3a3c user: Victor Stinner date: Wed Jul 17 21:53:23 2013 +0200 summary: Issue #18408: Fix _PyImport_LoadDynamicModule(), handle PyUnicode_FromFormat() failure files: Python/importdl.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Python/importdl.c b/Python/importdl.c --- a/Python/importdl.c +++ b/Python/importdl.c @@ -77,6 +77,8 @@ PyObject *msg = PyUnicode_FromFormat("dynamic module does not define " "init function (PyInit_%s)", shortname); + if (msg == NULL) + goto error; PyErr_SetImportError(msg, name, path); Py_DECREF(msg); goto error; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 22:11:54 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:11:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_PyEr?= =?utf-8?q?r=5FSetImportError=28=29=2C_handle_PyDict=5FSetItemString=28=29?= =?utf-8?q?_failure?= Message-ID: <3bwV4V4n1fz7Ll4@mail.python.org> http://hg.python.org/cpython/rev/573f7d485ce8 changeset: 84694:573f7d485ce8 user: Victor Stinner date: Wed Jul 17 21:54:25 2013 +0200 summary: Issue #18408: Fix PyErr_SetImportError(), handle PyDict_SetItemString() failure files: Python/errors.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -655,8 +655,11 @@ Py_INCREF(msg); PyTuple_SET_ITEM(args, 0, msg); - PyDict_SetItemString(kwargs, "name", name); - PyDict_SetItemString(kwargs, "path", path); + + if (PyDict_SetItemString(kwargs, "name", name) < 0) + return NULL; + if (PyDict_SetItemString(kwargs, "path", path) < 0) + return NULL; error = PyObject_Call(PyExc_ImportError, args, kwargs); if (error != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 22:11:55 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:11:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_list?= =?utf-8?q?pop=28=29=2C_handle_list=5Fass=5Fslice=28=29_failure?= Message-ID: <3bwV4W6g49z7Ll5@mail.python.org> http://hg.python.org/cpython/rev/97bb3bdf1443 changeset: 84695:97bb3bdf1443 user: Victor Stinner date: Wed Jul 17 21:58:01 2013 +0200 summary: Issue #18408: Fix listpop(), handle list_ass_slice() failure files: Objects/listobject.c | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -934,12 +934,10 @@ } Py_INCREF(v); status = list_ass_slice(self, i, i+1, (PyObject *)NULL); - assert(status >= 0); - /* Use status, so that in a release build compilers don't - * complain about the unused name. - */ - (void) status; - + if (status < 0) { + Py_DECREF(v); + return NULL; + } return v; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 22:11:57 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:11:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_Py?= =?utf-8?q?=5FReprEnter=28=29=2C_handle_PyList=5FAppend=28=29_failure?= Message-ID: <3bwV4Y1LwZz7Ljq@mail.python.org> http://hg.python.org/cpython/rev/2f5f1db8eb88 changeset: 84696:2f5f1db8eb88 user: Victor Stinner date: Wed Jul 17 21:58:41 2013 +0200 summary: Issue #18408: Fix Py_ReprEnter(), handle PyList_Append() failure files: Objects/object.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -1910,7 +1910,8 @@ if (PyList_GET_ITEM(list, i) == obj) return 1; } - PyList_Append(list, obj); + if (PyList_Append(list, obj) < 0) + return -1; return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 22:11:58 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:11:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_PyTy?= =?utf-8?q?pe=5FReady=28=29=2C_handle_=5FPyDict=5FSetItemId=28=29_failure?= Message-ID: <3bwV4Z3cLmz7LkY@mail.python.org> http://hg.python.org/cpython/rev/c2d90ff0780c changeset: 84697:c2d90ff0780c user: Victor Stinner date: Wed Jul 17 22:01:37 2013 +0200 summary: Issue #18408: Fix PyType_Ready(), handle _PyDict_SetItemId() failure files: Objects/typeobject.c | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4256,11 +4256,15 @@ PyObject *doc = PyUnicode_FromString(type->tp_doc); if (doc == NULL) goto error; - _PyDict_SetItemId(type->tp_dict, &PyId___doc__, doc); + if (_PyDict_SetItemId(type->tp_dict, &PyId___doc__, doc) < 0) { + Py_DECREF(doc); + goto error; + } Py_DECREF(doc); } else { - _PyDict_SetItemId(type->tp_dict, - &PyId___doc__, Py_None); + if (_PyDict_SetItemId(type->tp_dict, + &PyId___doc__, Py_None) < 0) + goto error; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 22:33:58 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:33:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Rewrite_?= =?utf-8?q?NEGATE=28=29_macro_in_longobject=2Ec_to_handle?= Message-ID: <3bwVYy4qJqzS6Y@mail.python.org> http://hg.python.org/cpython/rev/736514fb7b52 changeset: 84698:736514fb7b52 user: Victor Stinner date: Wed Jul 17 22:31:17 2013 +0200 summary: Issue #18408: Rewrite NEGATE() macro in longobject.c to handle PyLong_FromLong() failure files: Objects/longobject.c | 75 +++++++++++++++++++++---------- 1 files changed, 51 insertions(+), 24 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -70,11 +70,21 @@ /* If a freshly-allocated long is already shared, it must be a small integer, so negating it must go to PyLong_FromLong */ -#define NEGATE(x) \ - do if (Py_REFCNT(x) == 1) Py_SIZE(x) = -Py_SIZE(x); \ - else { PyObject* tmp=PyLong_FromLong(-MEDIUM_VALUE(x)); \ - Py_DECREF(x); (x) = (PyLongObject*)tmp; } \ - while(0) +Py_LOCAL_INLINE(void) +_PyLong_Negate(PyLongObject **x_p) +{ + PyLongObject *x; + + x = (PyLongObject *)*x_p; + if (Py_REFCNT(x) == 1) { + Py_SIZE(x) = -Py_SIZE(x); + return; + } + + *x_p = (PyLongObject *)PyLong_FromLong(-MEDIUM_VALUE(x)); + Py_DECREF(x); +} + /* For long multiplication, use the O(N**2) school algorithm unless * both operands contain more than KARATSUBA_CUTOFF digits (this * being an internal Python long digit, in base BASE). @@ -2357,10 +2367,21 @@ The quotient z has the sign of a*b; the remainder r has the sign of a, so a = b*z + r. */ - if ((Py_SIZE(a) < 0) != (Py_SIZE(b) < 0)) - NEGATE(z); - if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) - NEGATE(*prem); + if ((Py_SIZE(a) < 0) != (Py_SIZE(b) < 0)) { + _PyLong_Negate(&z); + if (z == NULL) { + Py_CLEAR(*prem); + return -1; + } + } + if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) { + _PyLong_Negate(prem); + if (*prem == NULL) { + Py_DECREF(z); + Py_CLEAR(*prem); + return -1; + } + } *pdiv = maybe_small_long(z); return 0; } @@ -2856,8 +2877,11 @@ borrow &= 1; /* Keep only one sign bit */ } assert(borrow == 0); - if (sign < 0) - NEGATE(z); + if (sign < 0) { + _PyLong_Negate(&z); + if (z == NULL) + return NULL; + } return long_normalize(z); } @@ -3348,8 +3372,11 @@ z = k_mul(a, b); /* Negate if exactly one of the inputs is negative. */ - if (((Py_SIZE(a) ^ Py_SIZE(b)) < 0) && z) - NEGATE(z); + if (((Py_SIZE(a) ^ Py_SIZE(b)) < 0) && z) { + _PyLong_Negate(&z); + if (z == NULL) + return NULL; + } return (PyObject *)z; } @@ -3796,7 +3823,9 @@ Py_DECREF(c); c = temp; temp = NULL; - NEGATE(c); + _PyLong_Negate(&c); + if (c == NULL) + goto Error; } /* if modulus == 1: @@ -3896,10 +3925,7 @@ goto Done; Error: - if (z != NULL) { - Py_DECREF(z); - z = NULL; - } + Py_CLEAR(z); /* fall through */ Done: if (Py_SIZE(b) > FIVEARY_CUTOFF) { @@ -4029,10 +4055,10 @@ shiftby = PyLong_AsSsize_t((PyObject *)b); if (shiftby == -1L && PyErr_Occurred()) - goto lshift_error; + return NULL; if (shiftby < 0) { PyErr_SetString(PyExc_ValueError, "negative shift count"); - goto lshift_error; + return NULL; } /* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */ wordshift = shiftby / PyLong_SHIFT; @@ -4044,9 +4070,11 @@ ++newsize; z = _PyLong_New(newsize); if (z == NULL) - goto lshift_error; - if (Py_SIZE(a) < 0) - NEGATE(z); + return NULL; + if (Py_SIZE(a) < 0) { + assert(Py_REFCNT(z) == 1); + Py_SIZE(z) = -Py_SIZE(z); + } for (i = 0; i < wordshift; i++) z->ob_digit[i] = 0; accum = 0; @@ -4060,7 +4088,6 @@ else assert(!accum); z = long_normalize(z); - lshift_error: return (PyObject *) maybe_small_long(z); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 17 22:34:00 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 17 Jul 2013 22:34:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_longobject=2Ec=3A_add_an_a?= =?utf-8?q?ssertion_to_ensure_that_MEDIUM=5FVALUE=28=29_is_only_called_on?= Message-ID: <3bwVZ0039hz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/3e7683c49620 changeset: 84699:3e7683c49620 user: Victor Stinner date: Wed Jul 17 22:33:42 2013 +0200 summary: longobject.c: add an assertion to ensure that MEDIUM_VALUE() is only called on small integers (0 or 1 digit) files: Objects/longobject.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -17,7 +17,8 @@ #endif /* convert a PyLong of size 1, 0 or -1 to an sdigit */ -#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \ +#define MEDIUM_VALUE(x) (assert(-1 <= Py_SIZE(x) && Py_SIZE(x) <= 1), \ + Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \ (Py_SIZE(x) == 0 ? (sdigit)0 : \ (sdigit)(x)->ob_digit[0])) #define ABS(x) ((x) < 0 ? -(x) : (x)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 01:46:18 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 01:46:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_arra?= =?utf-8?q?y=5Findex=28=29=2C_handle_getarrayitem=28=29_failure?= Message-ID: <3bwZqt1Zjnz7LjY@mail.python.org> http://hg.python.org/cpython/rev/d85b0c355052 changeset: 84700:d85b0c355052 user: Victor Stinner date: Wed Jul 17 23:01:30 2013 +0200 summary: Issue #18408: Fix array_index(), handle getarrayitem() failure files: Modules/arraymodule.c | 33 ++++++++++++++++++++++++------ 1 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -968,8 +968,13 @@ Py_ssize_t i; for (i = 0; i < Py_SIZE(self); i++) { - PyObject *selfi = getarrayitem((PyObject *)self, i); - int cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); + PyObject *selfi; + int cmp; + + selfi = getarrayitem((PyObject *)self, i); + if (selfi == NULL) + return NULL; + cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); Py_DECREF(selfi); if (cmp > 0) count++; @@ -990,8 +995,13 @@ Py_ssize_t i; for (i = 0; i < Py_SIZE(self); i++) { - PyObject *selfi = getarrayitem((PyObject *)self, i); - int cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); + PyObject *selfi; + int cmp; + + selfi = getarrayitem((PyObject *)self, i); + if (selfi == NULL) + return NULL; + cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); Py_DECREF(selfi); if (cmp > 0) { return PyLong_FromLong((long)i); @@ -1016,6 +1026,8 @@ for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(self); i++) { PyObject *selfi = getarrayitem((PyObject *)self, i); + if (selfi == NULL) + return NULL; cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); Py_DECREF(selfi); } @@ -1028,8 +1040,13 @@ int i; for (i = 0; i < Py_SIZE(self); i++) { - PyObject *selfi = getarrayitem((PyObject *)self,i); - int cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); + PyObject *selfi; + int cmp; + + selfi = getarrayitem((PyObject *)self,i); + if (selfi == NULL) + return NULL; + cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); Py_DECREF(selfi); if (cmp > 0) { if (array_ass_slice(self, i, i+1, @@ -1068,7 +1085,9 @@ PyErr_SetString(PyExc_IndexError, "pop index out of range"); return NULL; } - v = getarrayitem((PyObject *)self,i); + v = getarrayitem((PyObject *)self, i); + if (v == NULL) + return NULL; if (array_ass_slice(self, i, i+1, (PyObject *)NULL) != 0) { Py_DECREF(v); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 01:46:19 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 01:46:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_arra?= =?utf-8?q?y=5Ftolist=28=29=2C_handle_PyList=5FSetItem=28=29_failure?= Message-ID: <3bwZqv3gQ5z7Ljt@mail.python.org> http://hg.python.org/cpython/rev/b05a6a6eb525 changeset: 84701:b05a6a6eb525 user: Victor Stinner date: Thu Jul 18 01:12:35 2013 +0200 summary: Issue #18408: Fix array_tolist(), handle PyList_SetItem() failure files: Modules/arraymodule.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -1027,7 +1027,7 @@ for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(self); i++) { PyObject *selfi = getarrayitem((PyObject *)self, i); if (selfi == NULL) - return NULL; + return -1; cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); Py_DECREF(selfi); } @@ -1405,13 +1405,16 @@ return NULL; for (i = 0; i < Py_SIZE(self); i++) { PyObject *v = getarrayitem((PyObject *)self, i); - if (v == NULL) { - Py_DECREF(list); - return NULL; - } - PyList_SetItem(list, i, v); + if (v == NULL) + goto error; + if (PyList_SetItem(list, i, v) < 0) + goto error; } return list; + +error: + Py_DECREF(list); + return NULL; } PyDoc_STRVAR(tolist_doc, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 01:46:20 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 01:46:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_dict?= =?utf-8?q?=5Frepr=28=29=2C_don=27t_call_PyObject=5FRepr=28=29_with_an_exc?= =?utf-8?q?eption_set?= Message-ID: <3bwZqw5YY0z7Ljt@mail.python.org> http://hg.python.org/cpython/rev/161de66cae49 changeset: 84702:161de66cae49 user: Victor Stinner date: Thu Jul 18 01:00:45 2013 +0200 summary: Issue #18408: Fix dict_repr(), don't call PyObject_Repr() with an exception set PyObject_Repr() can removes the current exception. For example, module_repr() calls PyErr_Clear() if calling loader.module_repr(mod) failed. files: Objects/dictobject.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1443,6 +1443,9 @@ Py_INCREF(value); s = PyObject_Repr(key); PyUnicode_Append(&s, colon); + if (s == NULL) + goto Done; + PyUnicode_AppendAndDel(&s, PyObject_Repr(value)); Py_DECREF(key); Py_DECREF(value); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 01:46:22 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 01:46:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318488=3A_=5Fpysql?= =?utf-8?q?ite=5Ffinal=5Fcallback=28=29_should_not_clear_the_exception_set?= =?utf-8?q?_by?= Message-ID: <3bwZqy0Lw2z7Ljj@mail.python.org> http://hg.python.org/cpython/rev/a2214ab0812e changeset: 84703:a2214ab0812e user: Victor Stinner date: Thu Jul 18 01:42:04 2013 +0200 summary: Issue #18488: _pysqlite_final_callback() should not clear the exception set by the last call to the step() method of a user function files: Modules/_sqlite/connection.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -697,6 +697,7 @@ PyObject** aggregate_instance; _Py_IDENTIFIER(finalize); int ok; + PyObject *exception, *value, *tb; #ifdef WITH_THREAD PyGILState_STATE threadstate; @@ -712,7 +713,15 @@ goto error; } + /* Keep the exception (if any) of the last call to step() */ + PyErr_Fetch(&exception, &value, &tb); + function_result = _PyObject_CallMethodId(*aggregate_instance, &PyId_finalize, ""); + + /* Restore the exception (if any) of the last call to step(), + but clear also the current exception if finalize() failed */ + PyErr_Restore(exception, value, tb); + Py_DECREF(*aggregate_instance); ok = 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 01:46:23 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 01:46:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_PyEval?= =?utf-8?q?=5FEvalFrameEx=28=29_and_PyEval=5FCallObjectWithKeywords=28=29_?= =?utf-8?q?now_fail?= Message-ID: <3bwZqz3VFVz7Ljj@mail.python.org> http://hg.python.org/cpython/rev/48a869a39e2d changeset: 84704:48a869a39e2d user: Victor Stinner date: Thu Jul 18 01:41:08 2013 +0200 summary: Issue #18408: PyEval_EvalFrameEx() and PyEval_CallObjectWithKeywords() now fail with an assertion error if they are called with an exception set (PyErr_Occurred()). If these functions are called with an exception set, the exception may be cleared and so the caller looses its exception. Add also assertions to PyEval_CallObjectWithKeywords() and call_function() to check if the function succeed with no exception set, or the function failed with an exception set. files: Modules/_io/bufferedio.c | 5 +++++ Python/ceval.c | 26 ++++++++++++++++++++++++++ Python/errors.c | 11 +++++++++++ 3 files changed, 42 insertions(+), 0 deletions(-) diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -663,6 +663,11 @@ _set_BlockingIOError(char *msg, Py_ssize_t written) { PyObject *err; +#ifdef Py_DEBUG + /* in debug mode, PyEval_EvalFrameEx() fails with an assertion error + if an exception is set when it is called */ + PyErr_Clear(); +#endif err = PyObject_CallFunction(PyExc_BlockingIOError, "isn", errno, msg, written); if (err) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1203,6 +1203,13 @@ if (throwflag) /* support for generator.throw() */ goto error; +#ifdef Py_DEBUG + /* PyEval_EvalFrameEx() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller looses its exception */ + assert(!PyErr_Occurred()); +#endif + for (;;) { #ifdef WITH_TSC if (inst1 == 0) { @@ -1223,6 +1230,7 @@ #endif assert(stack_pointer >= f->f_valuestack); /* else underflow */ assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */ + assert(!PyErr_Occurred()); /* Do periodic things. Doing this every time through the loop would add too much overhead, so we do it @@ -3125,6 +3133,8 @@ break; READ_TIMESTAMP(loop1); + assert(!PyErr_Occurred()); + } /* main loop */ assert(why != WHY_YIELD); @@ -3137,6 +3147,9 @@ if (why != WHY_RETURN) retval = NULL; + assert((retval != NULL && !PyErr_Occurred()) + || (retval == NULL && PyErr_Occurred())); + fast_yield: if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) { /* The purpose of this block is to put aside the generator's exception @@ -4044,6 +4057,13 @@ { PyObject *result; +#ifdef Py_DEBUG + /* PyEval_CallObjectWithKeywords() must not be called with an exception + set, because it may clear it (directly or indirectly) + and so the caller looses its exception */ + assert(!PyErr_Occurred()); +#endif + if (arg == NULL) { arg = PyTuple_New(0); if (arg == NULL) @@ -4066,6 +4086,9 @@ result = PyObject_Call(func, arg, kw); Py_DECREF(arg); + + assert((result != NULL && !PyErr_Occurred()) + || (result == NULL && PyErr_Occurred())); return result; } @@ -4228,6 +4251,9 @@ Py_DECREF(w); PCALL(PCALL_POP); } + + assert((x != NULL && !PyErr_Occurred()) + || (x == NULL && PyErr_Occurred())); return x; } diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -71,6 +71,11 @@ if (value == NULL || !PyExceptionInstance_Check(value)) { /* We must normalize the value right now */ PyObject *args, *fixed_value; +#ifdef Py_DEBUG + /* in debug mode, PyEval_EvalFrameEx() fails with an assertion + error if an exception is set when it is called */ + PyErr_Clear(); +#endif if (value == NULL || value == Py_None) args = PyTuple_New(0); else if (PyTuple_Check(value)) { @@ -707,6 +712,12 @@ va_start(vargs); #endif +#ifdef Py_DEBUG + /* in debug mode, PyEval_EvalFrameEx() fails with an assertion error + if an exception is set when it is called */ + PyErr_Clear(); +#endif + string = PyUnicode_FromFormatV(format, vargs); PyErr_SetObject(exception, string); Py_XDECREF(string); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 01:57:33 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 01:57:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_=5Fp?= =?utf-8?q?ysqlite=5Ffetch=5Fone=5Frow=28=29=2C_in_debug_mode=2C_don=27t_c?= =?utf-8?q?all?= Message-ID: <3bwb4s5GVCz7Ljw@mail.python.org> http://hg.python.org/cpython/rev/9bae7696951f changeset: 84705:9bae7696951f user: Victor Stinner date: Thu Jul 18 01:54:37 2013 +0200 summary: Issue #18408: Fix _pysqlite_fetch_one_row(), in debug mode, don't call type_call() with an exception set files: Modules/_sqlite/cursor.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -339,6 +339,11 @@ if (self->connection->text_factory == (PyObject*)&PyUnicode_Type) { converted = PyUnicode_FromStringAndSize(val_str, nbytes); if (!converted) { +#ifdef Py_DEBUG + /* in debug mode, type_call() fails with an assertion + error if an exception is set when it is called */ + PyErr_Clear(); +#endif colname = sqlite3_column_name(self->statement->st, i); if (!colname) { colname = ""; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 01:57:35 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 01:57:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_PyObject?= =?utf-8?b?X1N0cigpLCBQeU9iamVjdF9SZXByKCkgYW5kIHR5cGVfY2FsbCgpIG5vdyBm?= =?utf-8?q?ail_with_an?= Message-ID: <3bwb4v08Ffz7Ljy@mail.python.org> http://hg.python.org/cpython/rev/5bd9db528aed changeset: 84706:5bd9db528aed user: Victor Stinner date: Thu Jul 18 01:49:30 2013 +0200 summary: Issue #18408: PyObject_Str(), PyObject_Repr() and type_call() now fail with an assertion error if they are called with an exception set (PyErr_Occurred()). As PyEval_EvalFrameEx(), they may clear the current exception and so the caller looses its exception. files: Objects/object.c | 16 ++++++++++++++++ Objects/typeobject.c | 7 +++++++ 2 files changed, 23 insertions(+), 0 deletions(-) diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -377,6 +377,14 @@ if (Py_TYPE(v)->tp_repr == NULL) return PyUnicode_FromFormat("<%s object at %p>", v->ob_type->tp_name, v); + +#ifdef Py_DEBUG + /* PyObject_Repr() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller looses its exception */ + assert(!PyErr_Occurred()); +#endif + res = (*v->ob_type->tp_repr)(v); if (res == NULL) return NULL; @@ -408,6 +416,7 @@ #endif if (v == NULL) return PyUnicode_FromString(""); + if (PyUnicode_CheckExact(v)) { #ifndef Py_DEBUG if (PyUnicode_READY(v) < 0) @@ -419,6 +428,13 @@ if (Py_TYPE(v)->tp_str == NULL) return PyObject_Repr(v); +#ifdef Py_DEBUG + /* PyObject_Str() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller looses its exception */ + assert(!PyErr_Occurred()); +#endif + /* It is possible for a type to have a tp_str representation that loops infinitely. */ if (Py_EnterRecursiveCall(" while getting the str of an object")) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -736,6 +736,13 @@ return NULL; } +#ifdef Py_DEBUG + /* type_call() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller looses its exception */ + assert(!PyErr_Occurred()); +#endif + obj = type->tp_new(type, args, kwds); if (obj != NULL) { /* Ugly exception: when the call was type(something), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 02:31:43 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 02:31:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_PyIn?= =?utf-8?b?aXRfX2N1cnNlc19wYW5lbCgpLCBoYW5kbGUgaW1wb3J0X2N1cnNlcygpIGZh?= =?utf-8?q?ilure?= Message-ID: <3bwbrH3z5tzRp9@mail.python.org> http://hg.python.org/cpython/rev/ddff866d820d changeset: 84707:ddff866d820d user: Victor Stinner date: Thu Jul 18 02:31:21 2013 +0200 summary: Issue #18408: Fix PyInit__curses_panel(), handle import_curses() failure Don't call PyErr_NewException() if an exception is set, or type_call() would fail with an assertion error. files: Modules/_curses_panel.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -513,6 +513,8 @@ goto fail; import_curses(); + if (PyErr_Occurred()) + goto fail; /* For exception _curses_panel.error */ _curses_panelstate(m)->PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL); -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jul 18 05:51:24 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 18 Jul 2013 05:51:24 +0200 Subject: [Python-checkins] Daily reference leaks (ddff866d820d): sum=0 Message-ID: results for ddff866d820d on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogoSDQzp', '-x'] From python-checkins at python.org Thu Jul 18 22:46:49 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 22:46:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_a_compiler_warning_on_?= =?utf-8?q?FreeBSD?= Message-ID: <3bx6pK47GPz7Ljd@mail.python.org> http://hg.python.org/cpython/rev/4c1945554edb changeset: 84708:4c1945554edb user: Victor Stinner date: Thu Jul 18 02:43:47 2013 +0200 summary: Fix a compiler warning on FreeBSD Modules/python.c:40: warning: ISO C90 forbids mixed declarations and code files: Modules/python.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/python.c b/Modules/python.c --- a/Modules/python.c +++ b/Modules/python.c @@ -23,6 +23,9 @@ wchar_t **argv_copy2; int i, res; char *oldloc; +#ifdef __FreeBSD__ + fp_except_t m; +#endif argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); @@ -37,8 +40,6 @@ * exceptions by default. Here we disable them. */ #ifdef __FreeBSD__ - fp_except_t m; - m = fpgetmask(); fpsetmask(m & ~FP_X_OFL); #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 22:46:50 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 22:46:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_=5Fe?= =?utf-8?q?lementtree=2Ec=2C_don=27t_call_Python_function_from_an_expat?= Message-ID: <3bx6pL66kFz7Lm0@mail.python.org> http://hg.python.org/cpython/rev/6ec0e9347dd4 changeset: 84709:6ec0e9347dd4 user: Victor Stinner date: Thu Jul 18 22:46:14 2013 +0200 summary: Issue #18408: Fix _elementtree.c, don't call Python function from an expat handler if a Python exception is set files: Modules/_elementtree.c | 28 ++++++++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -2831,6 +2831,9 @@ if (data_len < 2 || data_in[0] != '&') return; + if (PyErr_Occurred()) + return; + key = PyUnicode_DecodeUTF8(data_in + 1, data_len - 2, "strict"); if (!key) return; @@ -2871,6 +2874,9 @@ PyObject* attrib; int ok; + if (PyErr_Occurred()) + return; + /* tag name */ tag = makeuniversal(self, tag_in); if (!tag) @@ -2929,6 +2935,9 @@ PyObject* data; PyObject* res; + if (PyErr_Occurred()) + return; + data = PyUnicode_DecodeUTF8(data_in, data_len, "strict"); if (!data) return; /* parser will look for errors */ @@ -2952,6 +2961,9 @@ PyObject* tag; PyObject* res = NULL; + if (PyErr_Occurred()) + return; + if (TreeBuilder_CheckExact(self->target)) /* shortcut */ /* the standard tree builder doesn't look at the end tag */ @@ -2976,6 +2988,9 @@ PyObject* sprefix = NULL; PyObject* suri = NULL; + if (PyErr_Occurred()) + return; + suri = PyUnicode_DecodeUTF8(uri, strlen(uri), "strict"); if (!suri) return; @@ -3000,6 +3015,9 @@ static void expat_end_ns_handler(XMLParserObject* self, const XML_Char* prefix_in) { + if (PyErr_Occurred()) + return; + treebuilder_handle_namespace( (TreeBuilderObject*) self->target, 0, NULL, NULL ); @@ -3011,6 +3029,9 @@ PyObject* comment; PyObject* res; + if (PyErr_Occurred()) + return; + if (self->handle_comment) { comment = PyUnicode_DecodeUTF8(comment_in, strlen(comment_in), "strict"); if (comment) { @@ -3033,6 +3054,9 @@ PyObject *parser_doctype = NULL; PyObject *res = NULL; + if (PyErr_Occurred()) + return; + doctype_name_obj = makeuniversal(self, doctype_name); if (!doctype_name_obj) return; @@ -3101,6 +3125,9 @@ PyObject* data; PyObject* res; + if (PyErr_Occurred()) + return; + if (self->handle_pi) { target = PyUnicode_DecodeUTF8(target_in, strlen(target_in), "strict"); data = PyUnicode_DecodeUTF8(data_in, strlen(data_in), "strict"); @@ -3273,6 +3300,7 @@ { int ok; + assert(!PyErr_Occurred()); ok = EXPAT(Parse)(self->parser, data, data_len, final); if (PyErr_Occurred()) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 23:43:44 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 23:43:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318501=2C_=2318408?= =?utf-8?q?=3A_Fix_expat_handlers_in_pyexpat=2C_don=27t_call_Python?= Message-ID: <3bx8406xwpz7LkS@mail.python.org> http://hg.python.org/cpython/rev/5a6cdc0d7de1 changeset: 84710:5a6cdc0d7de1 user: Victor Stinner date: Thu Jul 18 23:17:01 2013 +0200 summary: Issue #18501, #18408: Fix expat handlers in pyexpat, don't call Python functions if a Python exception was raised files: Modules/pyexpat.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -402,6 +402,10 @@ my_CharacterDataHandler(void *userData, const XML_Char *data, int len) { xmlparseobject *self = (xmlparseobject *) userData; + + if (PyErr_Occurred()) + return; + if (self->buffer == NULL) call_character_handler(self, data, len); else { @@ -436,6 +440,9 @@ PyObject *container, *rv, *args; int i, max; + if (PyErr_Occurred()) + return; + if (flush_character_buffer(self) < 0) return; /* Set max to the number of slots filled in atts[]; max/2 is @@ -519,6 +526,8 @@ INIT \ \ if (have_handler(self, NAME)) { \ + if (PyErr_Occurred()) \ + return RETURN; \ if (flush_character_buffer(self) < 0) \ return RETURN; \ args = Py_BuildValue PARAM_FORMAT ;\ @@ -633,6 +642,9 @@ PyObject *rv = NULL; PyObject *modelobj, *nameobj; + if (PyErr_Occurred()) + return; + if (flush_character_buffer(self) < 0) goto finally; modelobj = conv_content_model(model, (conv_string_to_unicode)); @@ -1125,6 +1137,9 @@ void *data; unsigned int kind; + if (PyErr_Occurred()) + return XML_STATUS_ERROR; + if (template_buffer[1] == 0) { for (i = 0; i < 256; i++) template_buffer[i] = i; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 23:58:19 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 23:58:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRml4IHBvc2l4X2No?= =?utf-8?q?flags=28=29=3A_return=5Fvalue_was_uninitialized_when_follow=5Fs?= =?utf-8?q?ymlinks=3DFalse?= Message-ID: <3bx8Nq6CRDz7Lk4@mail.python.org> http://hg.python.org/cpython/rev/8fe3daa11700 changeset: 84711:8fe3daa11700 branch: 3.3 parent: 84687:dd75dbed1135 user: Victor Stinner date: Thu Jul 18 23:57:35 2013 +0200 summary: Fix posix_chflags(): return_value was uninitialized when follow_symlinks=False whereas the fchmodat() function is not avaialble. files: Modules/posixmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2961,7 +2961,7 @@ unsigned long flags; int follow_symlinks = 1; int result; - PyObject *return_value; + PyObject *return_value = NULL; static char *keywords[] = {"path", "flags", "follow_symlinks", NULL}; memset(&path, 0, sizeof(path)); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 18 23:58:21 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 18 Jul 2013 23:58:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogKE1lcmdlIDMuMykgRml4IHBvc2l4X2NoZmxhZ3MoKTogcmV0dXJuX3Zh?= =?utf-8?q?lue_was_uninitialized_when?= Message-ID: <3bx8Ns1L48z7Ljn@mail.python.org> http://hg.python.org/cpython/rev/627d29169ba2 changeset: 84712:627d29169ba2 parent: 84710:5a6cdc0d7de1 parent: 84711:8fe3daa11700 user: Victor Stinner date: Thu Jul 18 23:58:08 2013 +0200 summary: (Merge 3.3) Fix posix_chflags(): return_value was uninitialized when follow_symlinks=False whereas the fchmodat() function is not avaialble. files: Modules/posixmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2778,7 +2778,7 @@ unsigned long flags; int follow_symlinks = 1; int result; - PyObject *return_value; + PyObject *return_value = NULL; static char *keywords[] = {"path", "flags", "follow_symlinks", NULL}; memset(&path, 0, sizeof(path)); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 19 02:05:56 2013 From: python-checkins at python.org (ethan.furman) Date: Fri, 19 Jul 2013 02:05:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_closes_issue18042_--_a_=60?= =?utf-8?q?unique=60_decorator_is_added_to_enum=2Epy?= Message-ID: <3bxCD46JQBz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/2079a517193b changeset: 84713:2079a517193b user: Ethan Furman date: Thu Jul 18 17:05:39 2013 -0700 summary: closes issue18042 -- a `unique` decorator is added to enum.py The docs also clarify the 'Interesting Example' duplicate-free enum is for demonstration purposes. files: Doc/library/enum.rst | 93 ++++++++++++++++++++++--------- Lib/enum.py | 16 +++++- Lib/test/test_enum.py | 35 +++++++++++- 3 files changed, 115 insertions(+), 29 deletions(-) diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -18,7 +18,10 @@ the enumeration itself can be iterated over. This module defines two enumeration classes that can be used to define unique -sets of names and values: :class:`Enum` and :class:`IntEnum`. +sets of names and values: :class:`Enum` and :class:`IntEnum`. It also defines +one decorator, :func:`unique`, that ensures only unique member values are +present in an enumeration. + Creating an Enum ---------------- @@ -146,6 +149,35 @@ >>> Shape(2) + +Ensuring unique enumeration values +================================== + +By default, enumerations allow multiple names as aliases for the same value. +When this behavior isn't desired, the following decorator can be used to +ensure each value is used only once in the enumeration: + +.. decorator:: unique + +A :keyword:`class` decorator specifically for enumerations. It searches an +enumeration's :attr:`__members__` gathering any aliases it finds; if any are +found :exc:`ValueError` is raised with the details:: + + >>> from enum import Enum, unique + >>> @unique + ... class Mistake(Enum): + ... one = 1 + ... two = 2 + ... three = 3 + ... four = 3 + Traceback (most recent call last): + ... + ValueError: duplicate values found in : four -> three + + +Iteration +========= + Iterating over the members of an enum does not provide the aliases:: >>> list(Shape) @@ -169,6 +201,7 @@ >>> [name for name, member in Shape.__members__.items() if member.name != name] ['alias_for_square'] + Comparisons ----------- @@ -462,32 +495,6 @@ True -UniqueEnum ----------- - -Raises an error if a duplicate member name is found instead of creating an -alias:: - - >>> class UniqueEnum(Enum): - ... def __init__(self, *args): - ... cls = self.__class__ - ... if any(self.value == e.value for e in cls): - ... a = self.name - ... e = cls(self.value).name - ... raise ValueError( - ... "aliases not allowed in UniqueEnum: %r --> %r" - ... % (a, e)) - ... - >>> class Color(UniqueEnum): - ... red = 1 - ... green = 2 - ... blue = 3 - ... grene = 2 - Traceback (most recent call last): - ... - ValueError: aliases not allowed in UniqueEnum: 'grene' --> 'green' - - OrderedEnum ----------- @@ -524,6 +531,38 @@ True +DuplicateFreeEnum +----------------- + +Raises an error if a duplicate member name is found instead of creating an +alias:: + + >>> class DuplicateFreeEnum(Enum): + ... def __init__(self, *args): + ... cls = self.__class__ + ... if any(self.value == e.value for e in cls): + ... a = self.name + ... e = cls(self.value).name + ... raise ValueError( + ... "aliases not allowed in DuplicateFreeEnum: %r --> %r" + ... % (a, e)) + ... + >>> class Color(DuplicateFreeEnum): + ... red = 1 + ... green = 2 + ... blue = 3 + ... grene = 2 + Traceback (most recent call last): + ... + ValueError: aliases not allowed in DuplicateFreeEnum: 'grene' --> 'green' + +.. note:: + + This is a useful example for subclassing Enum to add or change other + behaviors as well as disallowing aliases. If the only change desired is + no aliases allowed the :func:`unique` decorator can be used instead. + + Planet ------ diff --git a/Lib/enum.py b/Lib/enum.py --- a/Lib/enum.py +++ b/Lib/enum.py @@ -4,7 +4,7 @@ from collections import OrderedDict from types import MappingProxyType -__all__ = ['Enum', 'IntEnum'] +__all__ = ['Enum', 'IntEnum', 'unique'] class _RouteClassAttributeToGetattr: @@ -463,3 +463,17 @@ class IntEnum(int, Enum): """Enum where members are also (and must be) ints""" + + +def unique(enumeration): + """Class decorator for enumerations ensuring unique member values.""" + duplicates = [] + for name, member in enumeration.__members__.items(): + if name != member.name: + duplicates.append((name, member.name)) + if duplicates: + alias_details = ', '.join( + ["%s -> %s" % (alias, name) for (alias, name) in duplicates]) + raise ValueError('duplicate values found in %r: %s' % + (enumeration, alias_details)) + return enumeration diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2,7 +2,7 @@ import unittest from collections import OrderedDict from pickle import dumps, loads, PicklingError -from enum import Enum, IntEnum +from enum import Enum, IntEnum, unique # for pickle tests try: @@ -917,5 +917,38 @@ self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6)) +class TestUnique(unittest.TestCase): + + def test_unique_clean(self): + @unique + class Clean(Enum): + one = 1 + two = 'dos' + tres = 4.0 + @unique + class Cleaner(IntEnum): + single = 1 + double = 2 + triple = 3 + + def test_unique_dirty(self): + with self.assertRaisesRegex(ValueError, 'tres.*one'): + @unique + class Dirty(Enum): + one = 1 + two = 'dos' + tres = 1 + with self.assertRaisesRegex( + ValueError, + 'double.*single.*turkey.*triple', + ): + @unique + class Dirtier(IntEnum): + single = 1 + double = 1 + triple = 3 + turkey = 3 + + if __name__ == '__main__': unittest.main() -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 19 05:51:18 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 19 Jul 2013 05:51:18 +0200 Subject: [Python-checkins] Daily reference leaks (2079a517193b): sum=0 Message-ID: results for 2079a517193b on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogk6WNbC', '-x'] From python-checkins at python.org Fri Jul 19 11:14:23 2013 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 19 Jul 2013 11:14:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4NDgwOiBBZGQg?= =?utf-8?q?missing_PyType=5FReady_call_to_=5Felementtree_extension?= Message-ID: <3bxRNv73l2z7Ljd@mail.python.org> http://hg.python.org/cpython/rev/cd4c9d4bd88f changeset: 84714:cd4c9d4bd88f branch: 3.3 parent: 84711:8fe3daa11700 user: Ronald Oussoren date: Fri Jul 19 11:11:25 2013 +0200 summary: #18480: Add missing PyType_Ready call to _elementtree extension files: Misc/NEWS | 2 ++ Modules/_elementtree.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,8 @@ Library ------- +- Issue #18480: Add missing call to PyType_Ready to the _elementtree extension. + - Issue #17778: Fix test discovery for test_multiprocessing. (Patch by Zachary Ware.) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -100,6 +100,13 @@ #define JOIN_SET(p, flag) ((void*) ((Py_uintptr_t) (JOIN_OBJ(p)) | (flag))) #define JOIN_OBJ(p) ((PyObject*) ((Py_uintptr_t) (p) & ~(Py_uintptr_t)1)) +/* Types defined by this extension */ +static PyTypeObject Element_Type; +static PyTypeObject ElementIter_Type; +static PyTypeObject TreeBuilder_Type; +static PyTypeObject XMLParser_Type; + + /* glue functions (see the init function for details) */ static PyObject* elementtree_parseerror_obj; static PyObject* elementtree_deepcopy_obj; @@ -200,7 +207,6 @@ } ElementObject; -static PyTypeObject Element_Type; #define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type) @@ -2204,8 +2210,6 @@ PyObject *end_ns_event_obj; } TreeBuilderObject; -static PyTypeObject TreeBuilder_Type; - #define TreeBuilder_CheckExact(op) (Py_TYPE(op) == &TreeBuilder_Type) /* -------------------------------------------------------------------- */ @@ -2717,8 +2721,6 @@ } XMLParserObject; -static PyTypeObject XMLParser_Type; - #define XMLParser_CheckExact(op) (Py_TYPE(op) == &XMLParser_Type) /* helpers */ @@ -3653,6 +3655,8 @@ PyObject *m, *temp; /* Initialize object types */ + if (PyType_Ready(&ElementIter_Type) < 0) + return NULL; if (PyType_Ready(&TreeBuilder_Type) < 0) return NULL; if (PyType_Ready(&Element_Type) < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 19 11:14:25 2013 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 19 Jul 2013 11:14:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogKDMuMy0+ZGVmYXVsdCk6ICMxODQ4MDogQWRkIG1pc3NpbmcgUHlUeXBl?= =?utf-8?q?=5FReady_call_to_=5Felementtree_extension?= Message-ID: <3bxRNx1ys5z7Ljd@mail.python.org> http://hg.python.org/cpython/rev/7362722646f7 changeset: 84715:7362722646f7 parent: 84713:2079a517193b parent: 84714:cd4c9d4bd88f user: Ronald Oussoren date: Fri Jul 19 11:14:05 2013 +0200 summary: (3.3->default): #18480: Add missing PyType_Ready call to _elementtree extension files: Misc/NEWS | 2 ++ Modules/_elementtree.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -159,6 +159,8 @@ Library ------- +- Issue #18480: Add missing call to PyType_Ready to the _elementtree extension. + - Issue #17778: Fix test discovery for test_multiprocessing. (Patch by Zachary Ware.) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -59,6 +59,13 @@ #define JOIN_SET(p, flag) ((void*) ((Py_uintptr_t) (JOIN_OBJ(p)) | (flag))) #define JOIN_OBJ(p) ((PyObject*) ((Py_uintptr_t) (p) & ~(Py_uintptr_t)1)) +/* Types defined by this extension */ +static PyTypeObject Element_Type; +static PyTypeObject ElementIter_Type; +static PyTypeObject TreeBuilder_Type; +static PyTypeObject XMLParser_Type; + + /* glue functions (see the init function for details) */ static PyObject* elementtree_parseerror_obj; static PyObject* elementtree_deepcopy_obj; @@ -159,7 +166,6 @@ } ElementObject; -static PyTypeObject Element_Type; #define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type) @@ -2182,8 +2188,6 @@ PyObject *end_ns_event_obj; } TreeBuilderObject; -static PyTypeObject TreeBuilder_Type; - #define TreeBuilder_CheckExact(op) (Py_TYPE(op) == &TreeBuilder_Type) /* -------------------------------------------------------------------- */ @@ -2693,8 +2697,6 @@ } XMLParserObject; -static PyTypeObject XMLParser_Type; - #define XMLParser_CheckExact(op) (Py_TYPE(op) == &XMLParser_Type) /* helpers */ @@ -3654,6 +3656,8 @@ PyObject *m, *temp; /* Initialize object types */ + if (PyType_Ready(&ElementIter_Type) < 0) + return NULL; if (PyType_Ready(&TreeBuilder_Type) < 0) return NULL; if (PyType_Ready(&Element_Type) < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 19 12:04:06 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 19 Jul 2013 12:04:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2318479=3A_Changed?= =?utf-8?q?_venv_Activate=2Eps1_to_make_deactivate_a_function=2C_and?= Message-ID: <3bxSVG6dhwz7Lkl@mail.python.org> http://hg.python.org/cpython/rev/1ff5e7505696 changeset: 84716:1ff5e7505696 user: Vinay Sajip date: Fri Jul 19 11:03:55 2013 +0100 summary: Closes #18479: Changed venv Activate.ps1 to make deactivate a function, and removed Deactivate.ps1. files: Lib/venv/scripts/nt/Activate.ps1 | 51 +++++++++++------ Lib/venv/scripts/nt/Deactivate.ps1 | 19 ------ Misc/NEWS | 3 + 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/Lib/venv/scripts/nt/Activate.ps1 b/Lib/venv/scripts/nt/Activate.ps1 --- a/Lib/venv/scripts/nt/Activate.ps1 +++ b/Lib/venv/scripts/nt/Activate.ps1 @@ -1,25 +1,40 @@ +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + if (Test-Path function:_OLD_VIRTUAL_PROMPT) { + copy-item function:_OLD_VIRTUAL_PROMPT function:prompt + remove-item function:_OLD_VIRTUAL_PROMPT + } + + if (Test-Path env:_OLD_VIRTUAL_PYTHONHOME) { + copy-item env:_OLD_VIRTUAL_PYTHONHOME env:PYTHONHOME + remove-item env:_OLD_VIRTUAL_PYTHONHOME + } + + if (Test-Path env:_OLD_VIRTUAL_PATH) { + copy-item env:_OLD_VIRTUAL_PATH env:PATH + remove-item env:_OLD_VIRTUAL_PATH + } + + if (Test-Path env:VIRTUAL_ENV) { + remove-item env:VIRTUAL_ENV + } + + if (!$NonDestructive) { + # Self destruct! + remove-item function:deactivate + } +} + +deactivate -nondestructive + $env:VIRTUAL_ENV="__VENV_DIR__" -# Revert to original values -if (Test-Path function:_OLD_VIRTUAL_PROMPT) { - copy-item function:_OLD_VIRTUAL_PROMPT function:prompt - remove-item function:_OLD_VIRTUAL_PROMPT -} - -if (Test-Path env:_OLD_VIRTUAL_PYTHONHOME) { - copy-item env:_OLD_VIRTUAL_PYTHONHOME env:PYTHONHOME - remove-item env:_OLD_VIRTUAL_PYTHONHOME -} - -if (Test-Path env:_OLD_VIRTUAL_PATH) { - copy-item env:_OLD_VIRTUAL_PATH env:PATH - remove-item env:_OLD_VIRTUAL_PATH -} - # Set the prompt to include the env name +# Make sure _OLD_VIRTUAL_PROMPT is global +function global:_OLD_VIRTUAL_PROMPT {""} copy-item function:prompt function:_OLD_VIRTUAL_PROMPT -function prompt { - Write-Host -NoNewline -ForegroundColor Green '[__VENV_NAME__]' +function global:prompt { + Write-Host -NoNewline -ForegroundColor Green '__VENV_NAME__' _OLD_VIRTUAL_PROMPT } diff --git a/Lib/venv/scripts/nt/Deactivate.ps1 b/Lib/venv/scripts/nt/Deactivate.ps1 deleted file mode 100644 --- a/Lib/venv/scripts/nt/Deactivate.ps1 +++ /dev/null @@ -1,19 +0,0 @@ -# Revert to original values -if (Test-Path function:_OLD_VIRTUAL_PROMPT) { - copy-item function:_OLD_VIRTUAL_PROMPT function:prompt - remove-item function:_OLD_VIRTUAL_PROMPT -} - -if (Test-Path env:_OLD_VIRTUAL_PYTHONHOME) { - copy-item env:_OLD_VIRTUAL_PYTHONHOME env:PYTHONHOME - remove-item env:_OLD_VIRTUAL_PYTHONHOME -} - -if (Test-Path env:_OLD_VIRTUAL_PATH) { - copy-item env:_OLD_VIRTUAL_PATH env:PATH - remove-item env:_OLD_VIRTUAL_PATH -} - -if (Test-Path env:VIRTUAL_ENV) { - remove-item env:VIRTUAL_ENV -} diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -159,6 +159,9 @@ Library ------- +- Issue #18479: Changed venv Activate.ps1 to make deactivate a function, and + removed Deactivate.ps1. + - Issue #18480: Add missing call to PyType_Ready to the _elementtree extension. - Issue #17778: Fix test discovery for test_multiprocessing. (Patch by -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 19 18:03:31 2013 From: python-checkins at python.org (daniel.holth) Date: Fri, 19 Jul 2013 18:03:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_426=3A_update_json_schema?= Message-ID: <3bxcSz5c7TzT20@mail.python.org> http://hg.python.org/peps/rev/bc08ca2e52fb changeset: 5006:bc08ca2e52fb user: Daniel Holth date: Fri Jul 19 12:03:16 2013 -0400 summary: PEP 426: update json schema files: pep-0426/pydist-schema.json | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/pep-0426/pydist-schema.json b/pep-0426/pydist-schema.json --- a/pep-0426/pydist-schema.json +++ b/pep-0426/pydist-schema.json @@ -12,7 +12,7 @@ "generator": { "description": "Name and version of the program that produced this file.", "type": "string", - "pattern": "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])( \\((\\d+(\\.\\d+)*)((a|b|c|rc)(\\d+))?(\\.(post)(\\d+))?(\\.(dev)(\\d+))\\))?$" + "pattern": "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])( \\(.*\\))?$" }, "name": { "description": "The name of the distribution.", @@ -239,6 +239,9 @@ }, "document_name": { "type": "string" + }, + "extra_name" : { + "type": "string" } } } -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Jul 19 23:14:35 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 19 Jul 2013 23:14:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318408=3A_Fix_list?= =?utf-8?b?X2Fzc19zbGljZSgpLCBoYW5kbGUgbGlzdF9yZXNpemUoKSBmYWlsdXJl?= Message-ID: <3bxlMv6t53z7Ljd@mail.python.org> http://hg.python.org/cpython/rev/3f25a7dd8346 changeset: 84717:3f25a7dd8346 user: Victor Stinner date: Fri Jul 19 23:06:21 2013 +0200 summary: Issue #18408: Fix list_ass_slice(), handle list_resize() failure I tested the patch manually by injecting a fault using gdb: list items are correctly restored on failure. files: Objects/listobject.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -644,9 +644,14 @@ memcpy(recycle, &item[ilow], s); if (d < 0) { /* Delete -d items */ - memmove(&item[ihigh+d], &item[ihigh], - (Py_SIZE(a) - ihigh)*sizeof(PyObject *)); - list_resize(a, Py_SIZE(a) + d); + Py_ssize_t tail; + tail = (Py_SIZE(a) - ihigh) * sizeof(PyObject *); + memmove(&item[ihigh+d], &item[ihigh], tail); + if (list_resize(a, Py_SIZE(a) + d) < 0) { + memmove(&item[ihigh], &item[ihigh+d], tail); + memcpy(&item[ilow], recycle, s); + goto Error; + } item = a->ob_item; } else if (d > 0) { /* Insert d items */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 19 23:55:42 2013 From: python-checkins at python.org (richard.oudkerk) Date: Fri, 19 Jul 2013 23:55:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Prevent_dangli?= =?utf-8?q?ng_threads/process_warning_for_test=5Fmultiprocessing=2E?= Message-ID: <3bxmHL6sHhz7LjM@mail.python.org> http://hg.python.org/cpython/rev/d8103ebb27ff changeset: 84718:d8103ebb27ff branch: 3.3 parent: 84714:cd4c9d4bd88f user: Richard Oudkerk date: Fri Jul 19 22:53:42 2013 +0100 summary: Prevent dangling threads/process warning for test_multiprocessing. files: Lib/test/test_multiprocessing.py | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -3561,14 +3561,17 @@ try: lock = multiprocessing.RLock() except OSError: - raise unittest.SkipTest("OSError raises on RLock creation, see issue 3111!") - + raise unittest.SkipTest("OSError raises on RLock creation, " + "see issue 3111!") check_enough_semaphores() - util.get_temp_dir() # creates temp directory for use by all processes - multiprocessing.get_logger().setLevel(LOG_LEVEL) +def tearDownModule(): + # pause a bit so we don't get warning about dangling threads/processes + time.sleep(0.5) + + if __name__ == '__main__': unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 19 23:55:44 2013 From: python-checkins at python.org (richard.oudkerk) Date: Fri, 19 Jul 2013 23:55:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2Uu?= Message-ID: <3bxmHN1m9Tz7LjW@mail.python.org> http://hg.python.org/cpython/rev/eaa77b72bff4 changeset: 84719:eaa77b72bff4 parent: 84717:3f25a7dd8346 parent: 84718:d8103ebb27ff user: Richard Oudkerk date: Fri Jul 19 22:54:37 2013 +0100 summary: Merge. files: Lib/test/test_multiprocessing.py | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -3590,14 +3590,17 @@ try: lock = multiprocessing.RLock() except OSError: - raise unittest.SkipTest("OSError raises on RLock creation, see issue 3111!") - + raise unittest.SkipTest("OSError raises on RLock creation, " + "see issue 3111!") check_enough_semaphores() - util.get_temp_dir() # creates temp directory for use by all processes - multiprocessing.get_logger().setLevel(LOG_LEVEL) +def tearDownModule(): + # pause a bit so we don't get warning about dangling threads/processes + time.sleep(0.5) + + if __name__ == '__main__': unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 04:36:11 2013 From: python-checkins at python.org (ethan.furman) Date: Sat, 20 Jul 2013 04:36:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2318508_--_fix_=5Fv?= =?utf-8?q?alue2member=5Fmap_to_always_have_the_member=27s_value?= Message-ID: <3bxtVz47RYz7LjR@mail.python.org> http://hg.python.org/cpython/rev/37c427e3eb94 changeset: 84720:37c427e3eb94 user: Ethan Furman date: Fri Jul 19 19:35:56 2013 -0700 summary: Close #18508 -- fix _value2member_map to always have the member's value files: Lib/enum.py | 24 +++++++++++++----------- Lib/test/test_enum.py | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Lib/enum.py b/Lib/enum.py --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1,5 +1,3 @@ -"""Python Enumerations""" - import sys from collections import OrderedDict from types import MappingProxyType @@ -154,11 +152,13 @@ args = (args, ) # wrap it one more time if not use_args: enum_member = __new__(enum_class) - enum_member._value = value + original_value = value else: enum_member = __new__(enum_class, *args) - if not hasattr(enum_member, '_value'): - enum_member._value = member_type(*args) + original_value = member_type(*args) + if not hasattr(enum_member, '_value'): + enum_member._value = original_value + value = enum_member._value enum_member._member_type = member_type enum_member._name = member_name enum_member.__init__(*args) @@ -416,12 +416,14 @@ return value # by-value search for a matching enum member # see if it's in the reverse mapping (for hashable values) - if value in cls._value2member_map: - return cls._value2member_map[value] - # not there, now do long search -- O(n) behavior - for member in cls._member_map.values(): - if member.value == value: - return member + try: + if value in cls._value2member_map: + return cls._value2member_map[value] + except TypeError: + # not there, now do long search -- O(n) behavior + for member in cls._member_map.values(): + if member.value == value: + return member raise ValueError("%s is not a valid %s" % (value, cls.__name__)) def __repr__(self): diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -694,6 +694,7 @@ x = ('the-x', 1) y = ('the-y', 2) + self.assertIs(NEI.__new__, Enum.__new__) self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") globals()['NamedInt'] = NamedInt @@ -785,6 +786,7 @@ [AutoNumber.first, AutoNumber.second, AutoNumber.third], ) self.assertEqual(int(AutoNumber.second), 2) + self.assertEqual(AutoNumber.third.value, 3) self.assertIs(AutoNumber(1), AutoNumber.first) def test_inherited_new_from_enhanced_enum(self): @@ -916,6 +918,22 @@ self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80) self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6)) + def test_nonhash_value(self): + class AutoNumberInAList(Enum): + def __new__(cls): + value = [len(cls.__members__) + 1] + obj = object.__new__(cls) + obj._value = value + return obj + class ColorInAList(AutoNumberInAList): + red = () + green = () + blue = () + self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue]) + self.assertEqual(ColorInAList.red.value, [1]) + self.assertEqual(ColorInAList([1]), ColorInAList.red) + + class TestUnique(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 04:47:37 2013 From: python-checkins at python.org (ethan.furman) Date: Sat, 20 Jul 2013 04:47:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Change_=5Fnames_to_=5Fname?= =?utf-8?q?s=5F_since_the_latter_is_reserved_for_Enum_use=2E?= Message-ID: <3bxtm94KcTz7LjR@mail.python.org> http://hg.python.org/cpython/rev/511c4daac102 changeset: 84721:511c4daac102 user: Ethan Furman date: Fri Jul 19 19:47:21 2013 -0700 summary: Change _names to _names_ since the latter is reserved for Enum use. Before this change only the methods were _single_underscored_; now the attributes are as well. files: Lib/enum.py | 60 +++++++++++++++--------------- Lib/test/test_enum.py | 23 ++++++----- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/Lib/enum.py b/Lib/enum.py --- a/Lib/enum.py +++ b/Lib/enum.py @@ -125,11 +125,11 @@ # create our new Enum type enum_class = super().__new__(metacls, cls, bases, classdict) - enum_class._member_names = [] # names in definition order - enum_class._member_map = OrderedDict() # name->value map + enum_class._member_names_ = [] # names in definition order + enum_class._member_map_ = OrderedDict() # name->value map # Reverse value->name map for hashable values. - enum_class._value2member_map = {} + enum_class._value2member_map_ = {} # check for a __getnewargs__, and if not present sabotage # pickling, since it won't work anyway @@ -156,27 +156,27 @@ else: enum_member = __new__(enum_class, *args) original_value = member_type(*args) - if not hasattr(enum_member, '_value'): - enum_member._value = original_value - value = enum_member._value - enum_member._member_type = member_type - enum_member._name = member_name + if not hasattr(enum_member, '_value_'): + enum_member._value_ = original_value + value = enum_member._value_ + enum_member._member_type_ = member_type + enum_member._name_ = member_name enum_member.__init__(*args) # If another member with the same value was already defined, the # new member becomes an alias to the existing one. - for name, canonical_member in enum_class._member_map.items(): - if canonical_member.value == enum_member._value: + for name, canonical_member in enum_class._member_map_.items(): + if canonical_member.value == enum_member._value_: enum_member = canonical_member break else: # Aliases don't appear in member names (only in __members__). - enum_class._member_names.append(member_name) - enum_class._member_map[member_name] = enum_member + enum_class._member_names_.append(member_name) + enum_class._member_map_[member_name] = enum_member try: # This may fail if value is not hashable. We can't add the value # to the map, and by-value lookups for this value will be # linear. - enum_class._value2member_map[value] = enum_member + enum_class._value2member_map_[value] = enum_member except TypeError: pass @@ -221,10 +221,10 @@ return cls._create_(value, names, module=module, type=type) def __contains__(cls, member): - return isinstance(member, cls) and member.name in cls._member_map + return isinstance(member, cls) and member.name in cls._member_map_ def __dir__(self): - return ['__class__', '__doc__', '__members__'] + self._member_names + return ['__class__', '__doc__', '__members__'] + self._member_names_ @property def __members__(cls): @@ -234,7 +234,7 @@ is a read-only view of the internal mapping. """ - return MappingProxyType(cls._member_map) + return MappingProxyType(cls._member_map_) def __getattr__(cls, name): """Return the enum member matching `name` @@ -248,18 +248,18 @@ if _is_dunder(name): raise AttributeError(name) try: - return cls._member_map[name] + return cls._member_map_[name] except KeyError: raise AttributeError(name) from None def __getitem__(cls, name): - return cls._member_map[name] + return cls._member_map_[name] def __iter__(cls): - return (cls._member_map[name] for name in cls._member_names) + return (cls._member_map_[name] for name in cls._member_names_) def __len__(cls): - return len(cls._member_names) + return len(cls._member_names_) def __repr__(cls): return "" % cls.__name__ @@ -327,7 +327,7 @@ for base in bases: if (base is not Enum and issubclass(base, Enum) and - base._member_names): + base._member_names_): raise TypeError("Cannot extend enumerations") # base is now the last base in bases if not issubclass(base, Enum): @@ -417,21 +417,21 @@ # by-value search for a matching enum member # see if it's in the reverse mapping (for hashable values) try: - if value in cls._value2member_map: - return cls._value2member_map[value] + if value in cls._value2member_map_: + return cls._value2member_map_[value] except TypeError: # not there, now do long search -- O(n) behavior - for member in cls._member_map.values(): + for member in cls._member_map_.values(): if member.value == value: return member raise ValueError("%s is not a valid %s" % (value, cls.__name__)) def __repr__(self): return "<%s.%s: %r>" % ( - self.__class__.__name__, self._name, self._value) + self.__class__.__name__, self._name_, self._value_) def __str__(self): - return "%s.%s" % (self.__class__.__name__, self._name) + return "%s.%s" % (self.__class__.__name__, self._name_) def __dir__(self): return (['__class__', '__doc__', 'name', 'value']) @@ -442,10 +442,10 @@ return NotImplemented def __getnewargs__(self): - return (self._value, ) + return (self._value_, ) def __hash__(self): - return hash(self._name) + return hash(self._name_) # _RouteClassAttributeToGetattr is used to provide access to the `name` # and `value` properties of enum members while keeping some measure of @@ -456,11 +456,11 @@ @_RouteClassAttributeToGetattr def name(self): - return self._name + return self._name_ @_RouteClassAttributeToGetattr def value(self): - return self._value + return self._value_ class IntEnum(int, Enum): diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -516,7 +516,7 @@ def question(self): print(42) self.assertIsNot(type(Why.question), Why) - self.assertNotIn(Why.question, Why._member_names) + self.assertNotIn(Why.question, Why._member_names_) self.assertNotIn(Why.question, Why) def test_wrong_inheritance_order(self): @@ -777,10 +777,10 @@ def __new__(cls): value = len(cls.__members__) + 1 obj = object.__new__(cls) - obj._value = value + obj._value_ = value return obj def __int__(self): - return int(self._value) + return int(self._value_) self.assertEqual( list(AutoNumber), [AutoNumber.first, AutoNumber.second, AutoNumber.third], @@ -794,10 +794,10 @@ def __new__(cls): value = len(cls.__members__) + 1 obj = object.__new__(cls) - obj._value = value + obj._value_ = value return obj def __int__(self): - return int(self._value) + return int(self._value_) class Color(AutoNumber): red = () green = () @@ -810,7 +810,7 @@ def __new__(cls): value = len(cls.__members__) + 1 obj = int.__new__(cls, value) - obj._value = value + obj._value_ = value return obj class Color(AutoNumber): red = () @@ -823,19 +823,19 @@ class OrderedEnum(Enum): def __ge__(self, other): if self.__class__ is other.__class__: - return self._value >= other._value + return self._value_ >= other._value_ return NotImplemented def __gt__(self, other): if self.__class__ is other.__class__: - return self._value > other._value + return self._value_ > other._value_ return NotImplemented def __le__(self, other): if self.__class__ is other.__class__: - return self._value <= other._value + return self._value_ <= other._value_ return NotImplemented def __lt__(self, other): if self.__class__ is other.__class__: - return self._value < other._value + return self._value_ < other._value_ return NotImplemented class Grade(OrderedEnum): A = 5 @@ -847,6 +847,7 @@ self.assertLessEqual(Grade.F, Grade.C) self.assertLess(Grade.D, Grade.A) self.assertGreaterEqual(Grade.B, Grade.B) + def test_extending2(self): class Shade(Enum): def shade(self): @@ -923,7 +924,7 @@ def __new__(cls): value = [len(cls.__members__) + 1] obj = object.__new__(cls) - obj._value = value + obj._value_ = value return obj class ColorInAList(AutoNumberInAList): red = () -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 04:52:13 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 20 Jul 2013 04:52:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Make_the_GCC-4=2E8_compile?= =?utf-8?q?r_happy_by_moving_declarations_to_the_top_of_the?= Message-ID: <3bxtsT6Tkjz7LjR@mail.python.org> http://hg.python.org/cpython/rev/f6f28235e80f changeset: 84722:f6f28235e80f user: Raymond Hettinger date: Fri Jul 19 19:52:04 2013 -0700 summary: Make the GCC-4.8 compiler happy by moving declarations to the top of the function. files: Modules/_ctypes/libffi_osx/ffi.c | 11 +++++---- Modules/_ctypes/libffi_osx/x86/x86-ffi64.c | 11 ++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Modules/_ctypes/libffi_osx/ffi.c b/Modules/_ctypes/libffi_osx/ffi.c --- a/Modules/_ctypes/libffi_osx/ffi.c +++ b/Modules/_ctypes/libffi_osx/ffi.c @@ -38,12 +38,13 @@ /*@out@*/ ffi_type* arg) { /*@-usedef@*/ + ffi_type** ptr; if (arg == NULL || arg->elements == NULL || arg->size != 0 || arg->alignment != 0) return FFI_BAD_TYPEDEF; - ffi_type** ptr = &(arg->elements[0]); + ptr = &(arg->elements[0]); while ((*ptr) != NULL) { @@ -135,16 +136,16 @@ /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type* rtype, /*@dependent@*/ ffi_type** atypes) { + unsigned int bytes = 0; + unsigned int i; + ffi_type** ptr; + if (cif == NULL) return FFI_BAD_TYPEDEF; if (abi <= FFI_FIRST_ABI || abi > FFI_DEFAULT_ABI) return FFI_BAD_ABI; - unsigned int bytes = 0; - unsigned int i; - ffi_type** ptr; - cif->abi = abi; cif->arg_types = atypes; cif->nargs = nargs; diff --git a/Modules/_ctypes/libffi_osx/x86/x86-ffi64.c b/Modules/_ctypes/libffi_osx/x86/x86-ffi64.c --- a/Modules/_ctypes/libffi_osx/x86/x86-ffi64.c +++ b/Modules/_ctypes/libffi_osx/x86/x86-ffi64.c @@ -225,14 +225,16 @@ /* Merge the fields of structure. */ for (ptr = type->elements; *ptr != NULL; ptr++) { + int num, pos; + byte_offset = ALIGN(byte_offset, (*ptr)->alignment); - int num = classify_argument(*ptr, subclasses, byte_offset % 8); + num = classify_argument(*ptr, subclasses, byte_offset % 8); if (num == 0) return 0; - int pos = byte_offset / 8; + pos = byte_offset / 8; for (i = 0; i < num; i++) { @@ -589,11 +591,12 @@ void (*fun)(ffi_cif*, void*, void**, void*), void* user_data) { + volatile unsigned short* tramp; + if (cif->abi != FFI_UNIX64) return FFI_BAD_ABI; - volatile unsigned short* tramp = - (volatile unsigned short*)&closure->tramp[0]; + tramp = (volatile unsigned short*)&closure->tramp[0]; tramp[0] = 0xbb49; /* mov , %r11 */ *(void* volatile*)&tramp[1] = ffi_closure_unix64; -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jul 20 05:49:18 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 20 Jul 2013 05:49:18 +0200 Subject: [Python-checkins] Daily reference leaks (eaa77b72bff4): sum=0 Message-ID: results for eaa77b72bff4 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogQahWlt', '-x'] From python-checkins at python.org Sat Jul 20 14:12:20 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 14:12:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Use_strncat=28=29_instead_?= =?utf-8?q?of_strcat=28=29_to_silence_some_warnings=2E?= Message-ID: <3by7Hm4W8dz7LjM@mail.python.org> http://hg.python.org/cpython/rev/c92f4172d122 changeset: 84723:c92f4172d122 user: Christian Heimes date: Sat Jul 20 14:11:28 2013 +0200 summary: Use strncat() instead of strcat() to silence some warnings. CID 486616, CID 486617, CID 486615 files: Modules/ossaudiodev.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/ossaudiodev.c b/Modules/ossaudiodev.c --- a/Modules/ossaudiodev.c +++ b/Modules/ossaudiodev.c @@ -245,7 +245,7 @@ int arg; assert(strlen(fname) <= 30); - strcat(argfmt, fname); + strncat(argfmt, fname, 30); if (!PyArg_ParseTuple(args, argfmt, &arg)) return NULL; @@ -270,7 +270,7 @@ int arg = 0; assert(strlen(fname) <= 30); - strcat(argfmt, fname); + strncat(argfmt, fname, 30); if (!PyArg_ParseTuple(args, argfmt, &arg)) return NULL; @@ -290,7 +290,7 @@ int rv; assert(strlen(fname) <= 30); - strcat(argfmt, fname); + strncat(argfmt, fname, 30); if (!PyArg_ParseTuple(args, argfmt)) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 14:12:21 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 14:12:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_fishy_sizeof=28Py=5Fss?= =?utf-8?b?aXplX3QgKiku?= Message-ID: <3by7Hn6VCGz7LjM@mail.python.org> http://hg.python.org/cpython/rev/afd0153e06c1 changeset: 84724:afd0153e06c1 user: Christian Heimes date: Sat Jul 20 14:11:52 2013 +0200 summary: Fix fishy sizeof(Py_ssize_t *). sizeof(Py_ssize_t *) == sizeof(Py_ssize_t) but it's not a portable assumption. CID 486403 files: Modules/_ctypes/_ctypes.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1326,7 +1326,7 @@ if (stgdict->format == NULL) goto error; stgdict->ndim = itemdict->ndim + 1; - stgdict->shape = PyMem_Malloc(sizeof(Py_ssize_t *) * stgdict->ndim); + stgdict->shape = PyMem_Malloc(sizeof(Py_ssize_t) * stgdict->ndim); if (stgdict->shape == NULL) goto error; stgdict->shape[0] = length; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 14:19:56 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 14:19:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318327=3A_Fix_argu?= =?utf-8?q?ment_order_in_call_to_compatible=5Ffor=5Fassignment=28oldto=2C?= Message-ID: <3by7SX6B0hz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/a65856044ad4 changeset: 84725:a65856044ad4 user: Christian Heimes date: Sat Jul 20 14:19:46 2013 +0200 summary: Issue #18327: Fix argument order in call to compatible_for_assignment(oldto, newto, attr). The fix only affects the error message of __class__ assignment. CID 983564 files: Objects/typeobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3338,7 +3338,7 @@ "__class__ assignment: only for heap types"); return -1; } - if (compatible_for_assignment(newto, oldto, "__class__")) { + if (compatible_for_assignment(oldto, newto, "__class__")) { Py_INCREF(newto); Py_TYPE(self) = newto; Py_DECREF(oldto); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 14:48:42 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 14:48:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_missing_ch?= =?utf-8?q?eck_of_PyDict=5FSetItem=28=29=27s_return_value_in_PyEval=5FEval?= =?utf-8?q?CodeEx=28=29?= Message-ID: <3by85k1qbtzRPK@mail.python.org> http://hg.python.org/cpython/rev/13d5b245ca14 changeset: 84726:13d5b245ca14 branch: 3.3 parent: 84718:d8103ebb27ff user: Christian Heimes date: Sat Jul 20 14:48:10 2013 +0200 summary: Add missing check of PyDict_SetItem()'s return value in PyEval_EvalCodeEx() CID 486647 files: Python/ceval.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3333,7 +3333,9 @@ keyword); goto fail; } - PyDict_SetItem(kwdict, keyword, value); + if (PyDict_SetItem(kwdict, keyword, value) == -1) { + goto fail; + } continue; kw_found: if (GETLOCAL(j) != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 14:48:43 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 14:48:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Add_missing_check_of_PyDict=5FSetItem=28=29=27s_return_v?= =?utf-8?q?alue_in_PyEval=5FEvalCodeEx=28=29?= Message-ID: <3by85l3jLyz7Ljm@mail.python.org> http://hg.python.org/cpython/rev/29c6fe41e7f1 changeset: 84727:29c6fe41e7f1 parent: 84725:a65856044ad4 parent: 84726:13d5b245ca14 user: Christian Heimes date: Sat Jul 20 14:48:21 2013 +0200 summary: Add missing check of PyDict_SetItem()'s return value in PyEval_EvalCodeEx() CID 486647 files: Python/ceval.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3461,7 +3461,9 @@ keyword); goto fail; } - PyDict_SetItem(kwdict, keyword, value); + if (PyDict_SetItem(kwdict, keyword, value) == -1) { + goto fail; + } continue; kw_found: if (GETLOCAL(j) != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 14:52:50 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 14:52:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_missing_ch?= =?utf-8?q?eck_of_PyDict=5FSetItem=28=29=27s_return_value_in?= Message-ID: <3by8BV31pZzR92@mail.python.org> http://hg.python.org/cpython/rev/80a5c2c2fb8a changeset: 84728:80a5c2c2fb8a branch: 3.3 parent: 84726:13d5b245ca14 user: Christian Heimes date: Sat Jul 20 14:51:53 2013 +0200 summary: Add missing check of PyDict_SetItem()'s return value in _PyImport_FindExtensionObject() CID 486649 files: Python/import.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -553,7 +553,10 @@ mod = def->m_base.m_init(); if (mod == NULL) return NULL; - PyDict_SetItem(PyImport_GetModuleDict(), name, mod); + if (PyDict_SetItem(PyImport_GetModuleDict(), name, mod) == -1) { + Py_DECREF(mod); + return NULL; + } Py_DECREF(mod); } if (_PyState_AddModule(mod, def) < 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 14:52:51 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 14:52:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Add_missing_check_of_PyDict=5FSetItem=28=29=27s_return_v?= =?utf-8?q?alue_in?= Message-ID: <3by8BW4rBNz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/92e27be3dd62 changeset: 84729:92e27be3dd62 parent: 84727:29c6fe41e7f1 parent: 84728:80a5c2c2fb8a user: Christian Heimes date: Sat Jul 20 14:52:18 2013 +0200 summary: Add missing check of PyDict_SetItem()'s return value in _PyImport_FindExtensionObject() CID 486649 files: Python/import.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -585,7 +585,10 @@ mod = def->m_base.m_init(); if (mod == NULL) return NULL; - PyDict_SetItem(PyImport_GetModuleDict(), name, mod); + if (PyDict_SetItem(PyImport_GetModuleDict(), name, mod) == -1) { + Py_DECREF(mod); + return NULL; + } Py_DECREF(mod); } if (_PyState_AddModule(mod, def) < 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 14:57:39 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 14:57:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Check_return_v?= =?utf-8?q?alue_of_PyType=5FReady=28=26EncodingMapType=29?= Message-ID: <3by8J309PjzR92@mail.python.org> http://hg.python.org/cpython/rev/b719f041f849 changeset: 84730:b719f041f849 branch: 3.3 parent: 84728:80a5c2c2fb8a user: Christian Heimes date: Sat Jul 20 14:57:16 2013 +0200 summary: Check return value of PyType_Ready(&EncodingMapType) CID 486654 files: Objects/unicodeobject.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14164,7 +14164,8 @@ PyUnicode_2BYTE_KIND, linebreak, Py_ARRAY_LENGTH(linebreak)); - PyType_Ready(&EncodingMapType); + if (PyType_Ready(&EncodingMapType) < 0) + Py_FatalError("Can't initialize encoding map type"); if (PyType_Ready(&PyFieldNameIter_Type) < 0) Py_FatalError("Can't initialize field name iterator type"); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 14:57:40 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 14:57:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Check_return_value_of_PyType=5FReady=28=26EncodingMapTyp?= =?utf-8?q?e=29?= Message-ID: <3by8J4294Wz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/a6891949b54a changeset: 84731:a6891949b54a parent: 84729:92e27be3dd62 parent: 84730:b719f041f849 user: Christian Heimes date: Sat Jul 20 14:57:28 2013 +0200 summary: Check return value of PyType_Ready(&EncodingMapType) CID 486654 files: Objects/unicodeobject.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14578,7 +14578,8 @@ PyUnicode_2BYTE_KIND, linebreak, Py_ARRAY_LENGTH(linebreak)); - PyType_Ready(&EncodingMapType); + if (PyType_Ready(&EncodingMapType) < 0) + Py_FatalError("Can't initialize encoding map type"); if (PyType_Ready(&PyFieldNameIter_Type) < 0) Py_FatalError("Can't initialize field name iterator type"); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 15:02:00 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 15:02:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_missing_ch?= =?utf-8?q?eck_of_PyDict=5FSetItem=28=29=27s_return_value?= Message-ID: <3by8P40WBJz7Lkm@mail.python.org> http://hg.python.org/cpython/rev/656954ec54a1 changeset: 84732:656954ec54a1 branch: 3.3 parent: 84730:b719f041f849 user: Christian Heimes date: Sat Jul 20 15:01:26 2013 +0200 summary: Add missing check of PyDict_SetItem()'s return value CID 486659 files: Modules/_testcapimodule.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -120,7 +120,10 @@ for (i = 0; i < count; i++) { v = PyLong_FromLong(i); - PyDict_SetItem(dict, v, v); + if (PyDict_SetItem(dict, v, v) < 0) { + Py_DECREF(v); + return -1; + } Py_DECREF(v); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 15:02:01 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 15:02:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Add_missing_check_of_PyDict=5FSetItem=28=29=27s_return_v?= =?utf-8?q?alue?= Message-ID: <3by8P52SbDz7Lkj@mail.python.org> http://hg.python.org/cpython/rev/9d93a267b8a0 changeset: 84733:9d93a267b8a0 parent: 84731:a6891949b54a parent: 84732:656954ec54a1 user: Christian Heimes date: Sat Jul 20 15:01:36 2013 +0200 summary: Add missing check of PyDict_SetItem()'s return value CID 486659 files: Modules/_testcapimodule.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -120,7 +120,10 @@ for (i = 0; i < count; i++) { v = PyLong_FromLong(i); - PyDict_SetItem(dict, v, v); + if (PyDict_SetItem(dict, v, v) < 0) { + Py_DECREF(v); + return -1; + } Py_DECREF(v); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 15:13:12 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 15:13:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_missing_ch?= =?utf-8?q?eck_of_PyDict=5FUpdate=28=29=27s_return_value_in_=5Felementtree?= =?utf-8?q?=2Ec?= Message-ID: <3by8f00Sg5zSSM@mail.python.org> http://hg.python.org/cpython/rev/76bb3fe6ce8f changeset: 84734:76bb3fe6ce8f branch: 3.3 parent: 84732:656954ec54a1 user: Christian Heimes date: Sat Jul 20 15:12:09 2013 +0200 summary: Add missing check of PyDict_Update()'s return value in _elementtree.c CID 719637 files: Modules/_elementtree.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -347,7 +347,8 @@ Py_DECREF(attrib_str); if (attrib) - PyDict_Update(attrib, kwds); + if (PyDict_Update(attrib, kwds) < 0) + return NULL; return attrib; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 15:13:13 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 15:13:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Add_missing_check_of_PyDict=5FUpdate=28=29=27s_return_va?= =?utf-8?q?lue_in_=5Felementtree=2Ec?= Message-ID: <3by8f12QlZz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/e7305517260b changeset: 84735:e7305517260b parent: 84733:9d93a267b8a0 parent: 84734:76bb3fe6ce8f user: Christian Heimes date: Sat Jul 20 15:12:19 2013 +0200 summary: Add missing check of PyDict_Update()'s return value in _elementtree.c CID 719637 files: Modules/_elementtree.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -310,7 +310,8 @@ /* attrib can be NULL if PyDict_New failed */ if (attrib) - PyDict_Update(attrib, kwds); + if (PyDict_Update(attrib, kwds) < 0) + return NULL; return attrib; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 19:00:28 2013 From: python-checkins at python.org (mark.dickinson) Date: Sat, 20 Jul 2013 19:00:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTEz?= =?utf-8?q?=3A_Add_workaround_for_OS_X_10=2E8_cexp_bug_that_leads_to_wrong?= Message-ID: <3byFhD39fqz7Ljm@mail.python.org> http://hg.python.org/cpython/rev/ce771c2d0220 changeset: 84736:ce771c2d0220 branch: 3.3 parent: 84734:76bb3fe6ce8f user: Mark Dickinson date: Sat Jul 20 17:59:13 2013 +0100 summary: Issue #18513: Add workaround for OS X 10.8 cexp bug that leads to wrong cmath.rect(0.0,-0.0) results. files: Misc/NEWS | 3 +++ Modules/cmathmodule.c | 7 +++++++ 2 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,9 @@ Library ------- +- Issue #18513: Fix behaviour of cmath.rect w.r.t. signed zeros on OS X 10.8 + + gcc. + - Issue #18480: Add missing call to PyType_Ready to the _elementtree extension. - Issue #17778: Fix test discovery for test_multiprocessing. (Patch by diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1006,6 +1006,13 @@ else errno = 0; } + else if (phi == 0.0) { + /* Workaround for buggy results with phi=-0.0 on OS X 10.8. See + bugs.python.org/issue18513. */ + z.real = r; + z.imag = r * phi; + errno = 0; + } else { z.real = r * cos(phi); z.imag = r * sin(phi); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 19:00:29 2013 From: python-checkins at python.org (mark.dickinson) Date: Sat, 20 Jul 2013 19:00:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318513=3A_Add_workaround_for_OS_X_10=2E8_cexp_bu?= =?utf-8?q?g_that_leads_to_wrong?= Message-ID: <3byFhF5NY6z7Ljv@mail.python.org> http://hg.python.org/cpython/rev/ae769deb45b2 changeset: 84737:ae769deb45b2 parent: 84735:e7305517260b parent: 84736:ce771c2d0220 user: Mark Dickinson date: Sat Jul 20 18:00:06 2013 +0100 summary: Issue #18513: Add workaround for OS X 10.8 cexp bug that leads to wrong cmath.rect(0.0,-0.0) results. files: Misc/NEWS | 3 +++ Modules/cmathmodule.c | 7 +++++++ 2 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -159,6 +159,9 @@ Library ------- +- Issue #18513: Fix behaviour of cmath.rect w.r.t. signed zeros on OS X 10.8 + + gcc. + - Issue #18479: Changed venv Activate.ps1 to make deactivate a function, and removed Deactivate.ps1. diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1006,6 +1006,13 @@ else errno = 0; } + else if (phi == 0.0) { + /* Workaround for buggy results with phi=-0.0 on OS X 10.8. See + bugs.python.org/issue18513. */ + z.real = r; + z.imag = r * phi; + errno = 0; + } else { z.real = r * cos(phi); z.imag = r * sin(phi); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 19:35:33 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 20 Jul 2013 19:35:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=239177=3A_Calling_r?= =?utf-8?q?ead=28=29_or_write=28=29_now_raises_ValueError=2C_not?= Message-ID: <3byGSj0pq1z7LjR@mail.python.org> http://hg.python.org/cpython/rev/eda7e86bf03c changeset: 84738:eda7e86bf03c user: Antoine Pitrou date: Sat Jul 20 19:35:16 2013 +0200 summary: Issue #9177: Calling read() or write() now raises ValueError, not AttributeError, on a closed SSL socket. Patch by Senko Rasic. files: Lib/ssl.py | 4 ++++ Lib/test/test_ssl.py | 15 +++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 23 insertions(+), 0 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -402,6 +402,8 @@ Return zero-length string on EOF.""" self._checkClosed() + if not self._sslobj: + raise ValueError("Read on closed or unwrapped SSL socket.") try: if buffer is not None: v = self._sslobj.read(len, buffer) @@ -422,6 +424,8 @@ number of bytes of DATA actually transmitted.""" self._checkClosed() + if not self._sslobj: + raise ValueError("Write on closed or unwrapped SSL socket.") return self._sslobj.write(data) def getpeercert(self, binary_form=False): 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 @@ -2311,6 +2311,21 @@ self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR') self.assertIn("TypeError", stderr.getvalue()) + def test_read_write_after_close_raises_valuerror(self): + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(CERTFILE) + context.load_cert_chain(CERTFILE) + server = ThreadedEchoServer(context=context, chatty=False) + + with server: + s = context.wrap_socket(socket.socket()) + s.connect((HOST, server.port)) + s.close() + + self.assertRaises(ValueError, s.read, 1024) + self.assertRaises(ValueError, s.write, 'hello') + def test_main(verbose=False): if support.verbose: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1021,6 +1021,7 @@ Burton Radons Jeff Ramnani Brodie Rao +Senko Rasic Antti Rasinen Sridhar Ratnakumar Ysj Ray diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -159,6 +159,9 @@ Library ------- +- Issue #9177: Calling read() or write() now raises ValueError, not + AttributeError, on a closed SSL socket. Patch by Senko Rasic. + - Issue #18513: Fix behaviour of cmath.rect w.r.t. signed zeros on OS X 10.8 + gcc. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 19:36:25 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 20 Jul 2013 19:36:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_test=5Fssl=3A_use_a_bytest?= =?utf-8?q?ring_here?= Message-ID: <3byGTj1tSxz7LjR@mail.python.org> http://hg.python.org/cpython/rev/759f27056d93 changeset: 84739:759f27056d93 user: Antoine Pitrou date: Sat Jul 20 19:36:15 2013 +0200 summary: test_ssl: use a bytestring here files: Lib/test/test_ssl.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2324,7 +2324,7 @@ s.close() self.assertRaises(ValueError, s.read, 1024) - self.assertRaises(ValueError, s.write, 'hello') + self.assertRaises(ValueError, s.write, b'hello') def test_main(verbose=False): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 19:59:52 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 20 Jul 2013 19:59:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NTEz?= =?utf-8?q?=3A_Add_workaround_for_OS_X_10=2E8_cexp_bug_that_leads_to_wrong?= Message-ID: <3byH0m3Kvwz7LjR@mail.python.org> http://hg.python.org/cpython/rev/91374660355a changeset: 84740:91374660355a branch: 2.7 parent: 84666:a9f7c2d49149 user: Raymond Hettinger date: Sat Jul 20 10:56:58 2013 -0700 summary: Issue #18513: Add workaround for OS X 10.8 cexp bug that leads to wrong cmath.rect(0.0,-0.0) results. files: Misc/NEWS | 3 +++ Modules/cmathmodule.c | 7 +++++++ 2 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,9 @@ - Issue #18455: multiprocessing should not retry connect() with same socket. +- Issue #18513: Fix behaviour of cmath.rect w.r.t. signed zeros on OS X 10.8 + + gcc. + - Issue #18101: Tcl.split() now process Unicode strings nested in a tuple as it do with byte strings. diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1006,6 +1006,13 @@ else errno = 0; } + else if (phi == 0.0) { + /* Workaround for buggy results with phi=-0.0 on OS X 10.8. See + bugs.python.org/issue18513. */ + z.real = r; + z.imag = r * phi; + errno = 0; + } else { z.real = r * cos(phi); z.imag = r * sin(phi); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 22:19:00 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 22:19:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Check_return_v?= =?utf-8?q?alue_of_fstat=28=29_in__=5FPyImport=5FGetDynLoadFunc=28=29?= Message-ID: <3byL5J741tzR1l@mail.python.org> http://hg.python.org/cpython/rev/654268ff29b5 changeset: 84741:654268ff29b5 branch: 3.3 parent: 84736:ce771c2d0220 user: Christian Heimes date: Sat Jul 20 22:17:55 2013 +0200 summary: Check return value of fstat() in _PyImport_GetDynLoadFunc() CID 486250 files: Python/dynload_shlib.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -90,7 +90,9 @@ if (fp != NULL) { int i; struct stat statb; - fstat(fileno(fp), &statb); + if (fstat(fileno(fp), &statb) == -1) { + return PyErr_SetFromErrno(PyExc_IOError); + } for (i = 0; i < nhandles; i++) { if (statb.st_dev == handles[i].dev && statb.st_ino == handles[i].ino) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 22:19:02 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 22:19:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Check_return_value_of_fstat=28=29_in__=5FPyImport=5FGetD?= =?utf-8?q?ynLoadFunc=28=29?= Message-ID: <3byL5L2FX4zR1l@mail.python.org> http://hg.python.org/cpython/rev/222404bce3da changeset: 84742:222404bce3da parent: 84739:759f27056d93 parent: 84741:654268ff29b5 user: Christian Heimes date: Sat Jul 20 22:18:19 2013 +0200 summary: Check return value of fstat() in _PyImport_GetDynLoadFunc() CID 486250 files: Python/dynload_shlib.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -81,7 +81,9 @@ if (fp != NULL) { int i; struct stat statb; - fstat(fileno(fp), &statb); + if (fstat(fileno(fp), &statb) == -1) { + return PyErr_SetFromErrno(PyExc_IOError); + } for (i = 0; i < nhandles; i++) { if (statb.st_dev == handles[i].dev && statb.st_ino == handles[i].ino) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 22:42:15 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 22:42:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Check_return_v?= =?utf-8?q?alue_of_flush=5Fcharacter=5Fbuffer=28=29?= Message-ID: <3byLc74vK1z7Lk3@mail.python.org> http://hg.python.org/cpython/rev/366eebaad633 changeset: 84743:366eebaad633 branch: 3.3 parent: 84741:654268ff29b5 user: Christian Heimes date: Sat Jul 20 22:41:58 2013 +0200 summary: Check return value of flush_character_buffer() CID 486663 files: Modules/pyexpat.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1503,7 +1503,9 @@ if (self->buffer != NULL) { /* there is already a buffer */ if (self->buffer_used != 0) { - flush_character_buffer(self); + if (flush_character_buffer(self) < 0) { + return -1; + } } /* free existing buffer */ free(self->buffer); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 22:42:16 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 22:42:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Check_return_value_of_flush=5Fcharacter=5Fbuffer=28=29?= Message-ID: <3byLc86mpLz7LkZ@mail.python.org> http://hg.python.org/cpython/rev/be159dc35f8b changeset: 84744:be159dc35f8b parent: 84742:222404bce3da parent: 84743:366eebaad633 user: Christian Heimes date: Sat Jul 20 22:42:06 2013 +0200 summary: Check return value of flush_character_buffer() CID 486663 files: Modules/pyexpat.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1521,7 +1521,9 @@ if (self->buffer != NULL) { /* there is already a buffer */ if (self->buffer_used != 0) { - flush_character_buffer(self); + if (flush_character_buffer(self) < 0) { + return -1; + } } /* free existing buffer */ PyMem_Free(self->buffer); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 22:55:05 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 22:55:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Check_return_v?= =?utf-8?q?alue_of_PyEval=5FGetGlobals=28=29_for_NULL?= Message-ID: <3byLtx3Fh1z7Ll7@mail.python.org> http://hg.python.org/cpython/rev/8b8673ccd3d1 changeset: 84745:8b8673ccd3d1 branch: 3.3 parent: 84743:366eebaad633 user: Christian Heimes date: Sat Jul 20 22:54:25 2013 +0200 summary: Check return value of PyEval_GetGlobals() for NULL CID 486814 files: Modules/pyexpat.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -283,12 +283,17 @@ { PyThreadState *tstate = PyThreadState_GET(); PyFrameObject *f; - PyObject *res; + PyObject *res, *globals; if (c == NULL) return NULL; - f = PyFrame_New(tstate, c, PyEval_GetGlobals(), NULL); + globals = PyEval_GetGlobals(); + if (globals == NULL) { + return NULL; + } + + f = PyFrame_New(tstate, c, globals, NULL); if (f == NULL) return NULL; tstate->frame = f; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 20 22:55:06 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 20 Jul 2013 22:55:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Check_return_value_of_PyEval=5FGetGlobals=28=29_for_NULL?= Message-ID: <3byLty59xtz7LlW@mail.python.org> http://hg.python.org/cpython/rev/c5d128b201af changeset: 84746:c5d128b201af parent: 84744:be159dc35f8b parent: 84745:8b8673ccd3d1 user: Christian Heimes date: Sat Jul 20 22:54:39 2013 +0200 summary: Check return value of PyEval_GetGlobals() for NULL CID 486814 files: Modules/pyexpat.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -286,12 +286,17 @@ { PyThreadState *tstate = PyThreadState_GET(); PyFrameObject *f; - PyObject *res; + PyObject *res, *globals; if (c == NULL) return NULL; - f = PyFrame_New(tstate, c, PyEval_GetGlobals(), NULL); + globals = PyEval_GetGlobals(); + if (globals == NULL) { + return NULL; + } + + f = PyFrame_New(tstate, c, globals, NULL); if (f == NULL) return NULL; tstate->frame = f; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 00:09:00 2013 From: python-checkins at python.org (ned.deily) Date: Sun, 21 Jul 2013 00:09:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3NTMy?= =?utf-8?q?=3A_Prevent_exception_when_changing_key_sets_if_Options_menu_is?= =?utf-8?q?_empty=2E?= Message-ID: <3byNXD0VPJz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/f8df7c50132f changeset: 84747:f8df7c50132f branch: 2.7 parent: 84740:91374660355a user: Ned Deily date: Sat Jul 20 14:38:24 2013 -0700 summary: Issue #17532: Prevent exception when changing key sets if Options menu is empty. files: Lib/idlelib/EditorWindow.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -833,7 +833,11 @@ menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] for menubarItem in self.menudict.keys(): menu = self.menudict[menubarItem] - end = menu.index(END) + 1 + end = menu.index(END) + if end is None: + # Skip empty menus + continue + end += 1 for index in range(0, end): if menu.type(index) == 'command': accel = menu.entrycget(index, 'accelerator') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 00:09:01 2013 From: python-checkins at python.org (ned.deily) Date: Sun, 21 Jul 2013 00:09:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NTMy?= =?utf-8?q?=3A_Prevent_exception_when_changing_key_sets_if_Options_menu_is?= =?utf-8?q?_empty=2E?= Message-ID: <3byNXF2Ynjz7Ljf@mail.python.org> http://hg.python.org/cpython/rev/db6a22943a3f changeset: 84748:db6a22943a3f branch: 3.3 parent: 84745:8b8673ccd3d1 user: Ned Deily date: Sat Jul 20 15:06:26 2013 -0700 summary: Issue #17532: Prevent exception when changing key sets if Options menu is empty. files: Lib/idlelib/EditorWindow.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -821,7 +821,11 @@ menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] for menubarItem in self.menudict: menu = self.menudict[menubarItem] - end = menu.index(END) + 1 + end = menu.index(END) + if end is None: + # Skip empty menus + continue + end += 1 for index in range(0, end): if menu.type(index) == 'command': accel = menu.entrycget(index, 'accelerator') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 00:09:02 2013 From: python-checkins at python.org (ned.deily) Date: Sun, 21 Jul 2013 00:09:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317532=3A_merge_from_3=2E3?= Message-ID: <3byNXG4NTMz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/5643e873f06e changeset: 84749:5643e873f06e parent: 84746:c5d128b201af parent: 84748:db6a22943a3f user: Ned Deily date: Sat Jul 20 15:08:22 2013 -0700 summary: Issue #17532: merge from 3.3 files: Lib/idlelib/EditorWindow.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -821,7 +821,11 @@ menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] for menubarItem in self.menudict: menu = self.menudict[menubarItem] - end = menu.index(END) + 1 + end = menu.index(END) + if end is None: + # Skip empty menus + continue + end += 1 for index in range(0, end): if menu.type(index) == 'command': accel = menu.entrycget(index, 'accelerator') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 01:55:20 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 01:55:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Check_return_v?= =?utf-8?q?alue_of_PyObject=5FAsFileDescriptor=28=29_in_=5FPy=5FDisplaySou?= =?utf-8?b?cmNlTGluZSgp?= Message-ID: <3byQtw69f9z7LjR@mail.python.org> http://hg.python.org/cpython/rev/82e9a9f8be3c changeset: 84750:82e9a9f8be3c branch: 3.3 parent: 84745:8b8673ccd3d1 user: Christian Heimes date: Sun Jul 21 01:53:10 2013 +0200 summary: Check return value of PyObject_AsFileDescriptor() in _Py_DisplaySourceLine() for error CID 486768 files: Python/traceback.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -255,6 +255,11 @@ /* use the right encoding to decode the file as unicode */ fd = PyObject_AsFileDescriptor(binary); + if (fd < 0) { + Py_DECREF(io); + Py_DECREF(binary); + return NULL; + } found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; lseek(fd, 0, 0); /* Reset position */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 01:55:22 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 01:55:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Check_return_value_of_PyObject=5FAsFileDescriptor=28=29_?= =?utf-8?q?in_=5FPy=5FDisplaySourceLine=28=29?= Message-ID: <3byQty0zsyz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/19a8c3e36cfb changeset: 84751:19a8c3e36cfb parent: 84746:c5d128b201af parent: 84750:82e9a9f8be3c user: Christian Heimes date: Sun Jul 21 01:53:18 2013 +0200 summary: Check return value of PyObject_AsFileDescriptor() in _Py_DisplaySourceLine() for error CID 486768 files: Python/traceback.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -257,6 +257,11 @@ /* use the right encoding to decode the file as unicode */ fd = PyObject_AsFileDescriptor(binary); + if (fd < 0) { + Py_DECREF(io); + Py_DECREF(binary); + return NULL; + } found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; lseek(fd, 0, 0); /* Reset position */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 01:55:23 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 01:55:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3byQtz330zz7Ljp@mail.python.org> http://hg.python.org/cpython/rev/251c09a9d411 changeset: 84752:251c09a9d411 parent: 84751:19a8c3e36cfb parent: 84749:5643e873f06e user: Christian Heimes date: Sun Jul 21 01:54:15 2013 +0200 summary: merge files: Lib/idlelib/EditorWindow.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -821,7 +821,11 @@ menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] for menubarItem in self.menudict: menu = self.menudict[menubarItem] - end = menu.index(END) + 1 + end = menu.index(END) + if end is None: + # Skip empty menus + continue + end += 1 for index in range(0, end): if menu.type(index) == 'command': accel = menu.entrycget(index, 'accelerator') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 01:55:24 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 01:55:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_merge?= Message-ID: <3byQv053mNz7LkN@mail.python.org> http://hg.python.org/cpython/rev/a0bb8a1b71e0 changeset: 84753:a0bb8a1b71e0 branch: 3.3 parent: 84750:82e9a9f8be3c parent: 84748:db6a22943a3f user: Christian Heimes date: Sun Jul 21 01:54:26 2013 +0200 summary: merge files: Lib/idlelib/EditorWindow.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -821,7 +821,11 @@ menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] for menubarItem in self.menudict: menu = self.menudict[menubarItem] - end = menu.index(END) + 1 + end = menu.index(END) + if end is None: + # Skip empty menus + continue + end += 1 for index in range(0, end): if menu.type(index) == 'command': accel = menu.entrycget(index, 'accelerator') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 01:55:26 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 01:55:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3byQv206MLz7Lkh@mail.python.org> http://hg.python.org/cpython/rev/8e42d4d6ad06 changeset: 84754:8e42d4d6ad06 parent: 84752:251c09a9d411 parent: 84753:a0bb8a1b71e0 user: Christian Heimes date: Sun Jul 21 01:54:36 2013 +0200 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 02:04:53 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 02:04:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Propagate_erro?= =?utf-8?q?r_when_PyByteArray=5FResize=28=29_fails_in_bytearray=5Ftranslat?= =?utf-8?b?ZSgp?= Message-ID: <3byR5x62SGzRg7@mail.python.org> http://hg.python.org/cpython/rev/15ac20ee5b70 changeset: 84755:15ac20ee5b70 branch: 3.3 parent: 84753:a0bb8a1b71e0 user: Christian Heimes date: Sun Jul 21 02:04:35 2013 +0200 summary: Propagate error when PyByteArray_Resize() fails in bytearray_translate() CID 715334 files: Objects/bytearrayobject.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1506,7 +1506,10 @@ } /* Fix the size of the resulting string */ if (inlen > 0) - PyByteArray_Resize(result, output - output_start); + if (PyByteArray_Resize(result, output - output_start) < 0) { + Py_CLEAR(result); + goto done; + } done: if (tableobj != NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 02:04:55 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 02:04:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Propagate_error_when_PyByteArray=5FResize=28=29_fails_in?= =?utf-8?q?_bytearray=5Ftranslate=28=29?= Message-ID: <3byR5z129HzRg7@mail.python.org> http://hg.python.org/cpython/rev/12acefa9ec71 changeset: 84756:12acefa9ec71 parent: 84754:8e42d4d6ad06 parent: 84755:15ac20ee5b70 user: Christian Heimes date: Sun Jul 21 02:04:44 2013 +0200 summary: Propagate error when PyByteArray_Resize() fails in bytearray_translate() CID 715334 files: Objects/bytearrayobject.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1508,7 +1508,10 @@ } /* Fix the size of the resulting string */ if (inlen > 0) - PyByteArray_Resize(result, output - output_start); + if (PyByteArray_Resize(result, output - output_start) < 0) { + Py_CLEAR(result); + goto done; + } done: if (tableobj != NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 02:12:53 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 02:12:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Check_return_v?= =?utf-8?q?alue_of_lseek=28=29_in_=5FPy=5FDisplaySourceLine=28=29=2E?= Message-ID: <3byRH96WxnzSBR@mail.python.org> http://hg.python.org/cpython/rev/8fdb83492a58 changeset: 84757:8fdb83492a58 branch: 3.3 parent: 84755:15ac20ee5b70 user: Christian Heimes date: Sun Jul 21 02:12:35 2013 +0200 summary: Check return value of lseek() in _Py_DisplaySourceLine(). Also use portable SEEK_SET instead of 0. CID 1040639 files: Python/traceback.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -262,7 +262,13 @@ } found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; - lseek(fd, 0, 0); /* Reset position */ + /* Reset position */ + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + Py_DECREF(io); + Py_DECREF(binary); + PyMem_FREE(found_encoding); + return PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, filename); + } fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding); Py_DECREF(io); Py_DECREF(binary); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 02:12:55 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 02:12:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Check_return_value_of_lseek=28=29_in_=5FPy=5FDisplaySour?= =?utf-8?b?Y2VMaW5lKCku?= Message-ID: <3byRHC1RlRz7LjV@mail.python.org> http://hg.python.org/cpython/rev/228180598aab changeset: 84758:228180598aab parent: 84756:12acefa9ec71 parent: 84757:8fdb83492a58 user: Christian Heimes date: Sun Jul 21 02:12:44 2013 +0200 summary: Check return value of lseek() in _Py_DisplaySourceLine(). Also use portable SEEK_SET instead of 0. CID 1040639 files: Python/traceback.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -264,7 +264,13 @@ } found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; - lseek(fd, 0, 0); /* Reset position */ + /* Reset position */ + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + Py_DECREF(io); + Py_DECREF(binary); + PyMem_FREE(found_encoding); + return PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, filename); + } fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding); Py_DECREF(io); Py_DECREF(binary); -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 21 05:48:52 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 21 Jul 2013 05:48:52 +0200 Subject: [Python-checkins] Daily reference leaks (228180598aab): sum=0 Message-ID: results for 228180598aab on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogdBTIzt', '-x'] From python-checkins at python.org Sun Jul 21 10:51:16 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 21 Jul 2013 10:51:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_code_simplification_?= =?utf-8?q?by_eliminating_an_unnecessary_temporary_variable=2E?= Message-ID: <3byfnJ3wxlz7LjV@mail.python.org> http://hg.python.org/cpython/rev/f49a43dcdcef changeset: 84759:f49a43dcdcef user: Raymond Hettinger date: Sun Jul 21 01:51:07 2013 -0700 summary: Minor code simplification by eliminating an unnecessary temporary variable. files: Modules/_collectionsmodule.c | 18 ++++++------------ 1 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -491,7 +491,6 @@ b = NULL; } assert(leftindex > 0); - { PyObject **src, **dest; Py_ssize_t m = n; @@ -510,15 +509,13 @@ *(dest--) = *(src--); } while (--m); } - if (rightindex == -1) { - block *prevblock = rightblock->leftlink; assert(leftblock != rightblock); assert(b == NULL); b = rightblock; - CHECK_NOT_END(prevblock); - MARK_END(prevblock->rightlink); - rightblock = prevblock; + CHECK_NOT_END(rightblock->leftlink); + rightblock = rightblock->leftlink; + MARK_END(rightblock->rightlink); rightindex = BLOCKLEN - 1; } } @@ -538,7 +535,6 @@ b = NULL; } assert (rightindex < BLOCKLEN - 1); - { PyObject **src, **dest; Py_ssize_t m = -n; @@ -557,15 +553,13 @@ *(dest++) = *(src++); } while (--m); } - if (leftindex == BLOCKLEN) { - block *nextblock = leftblock->rightlink; assert(leftblock != rightblock); assert(b == NULL); b = leftblock; - CHECK_NOT_END(nextblock); - MARK_END(nextblock->leftlink); - leftblock = nextblock; + CHECK_NOT_END(leftblock->rightlink); + leftblock = leftblock->rightlink; + MARK_END(leftblock->leftlink); leftindex = 0; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 13:09:25 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 21 Jul 2013 13:09:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318519=2C_=2318408?= =?utf-8?q?=3A_Fix_sqlite_authorizer_callback?= Message-ID: <3byjrj5dj7z7LjR@mail.python.org> http://hg.python.org/cpython/rev/026593cbc006 changeset: 84760:026593cbc006 user: Victor Stinner date: Sun Jul 21 13:05:38 2013 +0200 summary: Issue #18519, #18408: Fix sqlite authorizer callback If a previous call to the authorizer callback failed and raised an exception, don't call the Python authorizer callback, but just return SQLITE_DENY. files: Modules/_sqlite/connection.c | 38 ++++++++++++++--------- 1 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -883,25 +883,33 @@ gilstate = PyGILState_Ensure(); #endif - ret = PyObject_CallFunction((PyObject*)user_arg, "issss", action, arg1, arg2, dbname, access_attempt_source); - if (!ret) { - if (_enable_callback_tracebacks) { - PyErr_Print(); + if (!PyErr_Occurred()) { + ret = PyObject_CallFunction((PyObject*)user_arg, "issss", action, arg1, arg2, dbname, access_attempt_source); + + if (!ret) { + if (_enable_callback_tracebacks) { + PyErr_Print(); + } else { + PyErr_Clear(); + } + + rc = SQLITE_DENY; } else { - PyErr_Clear(); + if (PyLong_Check(ret)) { + rc = _PyLong_AsInt(ret); + if (rc == -1 && PyErr_Occurred()) + rc = SQLITE_DENY; + } else { + rc = SQLITE_DENY; + } + Py_DECREF(ret); } - + } + else { + /* A previous call to the authorizer callback failed and raised an + exception: don't call the Python authorizer callback */ rc = SQLITE_DENY; - } else { - if (PyLong_Check(ret)) { - rc = _PyLong_AsInt(ret); - if (rc == -1 && PyErr_Occurred()) - rc = SQLITE_DENY; - } else { - rc = SQLITE_DENY; - } - Py_DECREF(ret); } #ifdef WITH_THREAD -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 13:26:06 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 21 Jul 2013 13:26:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318520=3A_Fix_init?= =?utf-8?q?sigs=28=29=2C_handle_PyOS=5FInitInterrupts=28=29_error?= Message-ID: <3bykCy27h3zRg7@mail.python.org> http://hg.python.org/cpython/rev/276477d5a548 changeset: 84761:276477d5a548 user: Victor Stinner date: Sun Jul 21 13:25:51 2013 +0200 summary: Issue #18520: Fix initsigs(), handle PyOS_InitInterrupts() error PyOS_InitInterrupts() can raise error when importing the signal module files: Python/pythonrun.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -2481,6 +2481,9 @@ PyOS_setsig(SIGXFSZ, SIG_IGN); #endif PyOS_InitInterrupts(); /* May imply initsignal() */ + if (PyErr_Occurred()) { + Py_FatalError("Py_Initialize: can't import signal"); + } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 16:23:10 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 16:23:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_reference_?= =?utf-8?q?and_memory_leaks_in_=5Ffreeze=5Fimportlib?= Message-ID: <3byp8G6Wjxz7LjP@mail.python.org> http://hg.python.org/cpython/rev/eb76c4201e56 changeset: 84762:eb76c4201e56 branch: 3.3 parent: 84757:8fdb83492a58 user: Christian Heimes date: Sun Jul 21 16:19:02 2013 +0200 summary: Fix reference and memory leaks in _freeze_importlib files: Modules/_freeze_importlib.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Modules/_freeze_importlib.c b/Modules/_freeze_importlib.c --- a/Modules/_freeze_importlib.c +++ b/Modules/_freeze_importlib.c @@ -72,6 +72,7 @@ if (n < text_size) { fprintf(stderr, "read too short: got %ld instead of %ld bytes\n", (long) n, (long) text_size); + free(text); return 1; } text[text_size] = '\0'; @@ -86,6 +87,7 @@ code = Py_CompileStringExFlags(text, "", Py_file_input, NULL, 0); + free(text); if (code == NULL) goto error; marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION); @@ -102,6 +104,7 @@ outfile = fopen(outpath, "w"); if (outfile == NULL) { fprintf(stderr, "cannot open '%s' for writing\n", outpath); + Py_DECREF(marshalled); return 1; } fprintf(outfile, "%s\n", header); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 16:23:12 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 16:23:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_reference_and_memory_leaks_in_=5Ffreeze=5Fimportlib?= Message-ID: <3byp8J1Gs5z7LjP@mail.python.org> http://hg.python.org/cpython/rev/c18bb06892e9 changeset: 84763:c18bb06892e9 parent: 84761:276477d5a548 parent: 84762:eb76c4201e56 user: Christian Heimes date: Sun Jul 21 16:19:16 2013 +0200 summary: Fix reference and memory leaks in _freeze_importlib files: Modules/_freeze_importlib.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Modules/_freeze_importlib.c b/Modules/_freeze_importlib.c --- a/Modules/_freeze_importlib.c +++ b/Modules/_freeze_importlib.c @@ -72,6 +72,7 @@ if (n < text_size) { fprintf(stderr, "read too short: got %ld instead of %ld bytes\n", (long) n, (long) text_size); + free(text); return 1; } text[text_size] = '\0'; @@ -86,6 +87,7 @@ code = Py_CompileStringExFlags(text, "", Py_file_input, NULL, 0); + free(text); if (code == NULL) goto error; marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION); @@ -102,6 +104,7 @@ outfile = fopen(outpath, "w"); if (outfile == NULL) { fprintf(stderr, "cannot open '%s' for writing\n", outpath); + Py_DECREF(marshalled); return 1; } fprintf(outfile, "%s\n", header); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 16:25:42 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 16:25:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTE0?= =?utf-8?q?=3A_Fix_unreachable_Py=5FDECREF=28=29_call_in_PyCData=5FFromBas?= =?utf-8?b?ZU9iaigp?= Message-ID: <3bypCB3dxZz7LjP@mail.python.org> http://hg.python.org/cpython/rev/25ffad2e12d6 changeset: 84764:25ffad2e12d6 branch: 3.3 parent: 84762:eb76c4201e56 user: Christian Heimes date: Sun Jul 21 16:24:51 2013 +0200 summary: Issue #18514: Fix unreachable Py_DECREF() call in PyCData_FromBaseObj() files: Misc/NEWS | 2 ++ Modules/_ctypes/_ctypes.c | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,8 @@ Library ------- +- Issue #18514: Fix unreachable Py_DECREF() call in PyCData_FromBaseObj() + - Issue #18513: Fix behaviour of cmath.rect w.r.t. signed zeros on OS X 10.8 + gcc. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2671,8 +2671,8 @@ cmem->b_index = index; } else { /* copy contents of adr */ if (-1 == PyCData_MallocBuffer(cmem, dict)) { + Py_DECREF(cmem); return NULL; - Py_DECREF(cmem); } memcpy(cmem->b_ptr, adr, dict->size); cmem->b_index = index; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 16:25:43 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 16:25:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318514=3A_Fix_unreachable_Py=5FDECREF=28=29_call?= =?utf-8?q?_in_PyCData=5FFromBaseObj=28=29?= Message-ID: <3bypCC5lh5z7Lk3@mail.python.org> http://hg.python.org/cpython/rev/afe119a3619f changeset: 84765:afe119a3619f parent: 84763:c18bb06892e9 parent: 84764:25ffad2e12d6 user: Christian Heimes date: Sun Jul 21 16:25:30 2013 +0200 summary: Issue #18514: Fix unreachable Py_DECREF() call in PyCData_FromBaseObj() files: Misc/NEWS | 2 ++ Modules/_ctypes/_ctypes.c | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -159,6 +159,8 @@ Library ------- +- Issue #18514: Fix unreachable Py_DECREF() call in PyCData_FromBaseObj() + - Issue #9177: Calling read() or write() now raises ValueError, not AttributeError, on a closed SSL socket. Patch by Senko Rasic. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2671,8 +2671,8 @@ cmem->b_index = index; } else { /* copy contents of adr */ if (-1 == PyCData_MallocBuffer(cmem, dict)) { + Py_DECREF(cmem); return NULL; - Py_DECREF(cmem); } memcpy(cmem->b_ptr, adr, dict->size); cmem->b_index = index; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 22:27:10 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 21 Jul 2013 22:27:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogbGV0J3Mgbm90IHJl?= =?utf-8?q?turn_NULL_from_functions_that_should_return_ints?= Message-ID: <3byyDG02GdzQlq@mail.python.org> http://hg.python.org/cpython/rev/34ca4dd47c54 changeset: 84766:34ca4dd47c54 branch: 3.3 parent: 84764:25ffad2e12d6 user: Benjamin Peterson date: Sun Jul 21 13:26:13 2013 -0700 summary: let's not return NULL from functions that should return ints files: Python/traceback.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -258,7 +258,7 @@ if (fd < 0) { Py_DECREF(io); Py_DECREF(binary); - return NULL; + return 0; } found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; @@ -267,7 +267,7 @@ Py_DECREF(io); Py_DECREF(binary); PyMem_FREE(found_encoding); - return PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, filename); + return 0; } fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding); Py_DECREF(io); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 22:27:11 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 21 Jul 2013 22:27:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3byyDH207WzQlq@mail.python.org> http://hg.python.org/cpython/rev/c72f4f076d29 changeset: 84767:c72f4f076d29 parent: 84765:afe119a3619f parent: 84766:34ca4dd47c54 user: Benjamin Peterson date: Sun Jul 21 13:26:27 2013 -0700 summary: merge 3.3 files: Python/traceback.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -260,7 +260,7 @@ if (fd < 0) { Py_DECREF(io); Py_DECREF(binary); - return NULL; + return 0; } found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; @@ -269,7 +269,7 @@ Py_DECREF(io); Py_DECREF(binary); PyMem_FREE(found_encoding); - return PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, filename); + return 0; } fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding); Py_DECREF(io); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 22:29:49 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 21 Jul 2013 22:29:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_fix_spacing?= Message-ID: <3byyHK6Zd7zRFD@mail.python.org> http://hg.python.org/cpython/rev/5607084e2204 changeset: 84768:5607084e2204 branch: 3.3 parent: 84766:34ca4dd47c54 user: Benjamin Peterson date: Sun Jul 21 13:29:37 2013 -0700 summary: fix spacing files: Python/traceback.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -322,7 +322,7 @@ strcpy(buf, " "); assert (strlen(buf) == 10); while (indent > 0) { - if(indent < 10) + if (indent < 10) buf[indent] = '\0'; err = PyFile_WriteString(buf, f); if (err != 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 22:29:51 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 21 Jul 2013 22:29:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3byyHM1MBbzSGt@mail.python.org> http://hg.python.org/cpython/rev/e82472e4fd97 changeset: 84769:e82472e4fd97 parent: 84767:c72f4f076d29 parent: 84768:5607084e2204 user: Benjamin Peterson date: Sun Jul 21 13:29:42 2013 -0700 summary: merge 3.3 files: Python/traceback.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -324,7 +324,7 @@ strcpy(buf, " "); assert (strlen(buf) == 10); while (indent > 0) { - if(indent < 10) + if (indent < 10) buf[indent] = '\0'; err = PyFile_WriteString(buf, f); if (err != 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 23:05:34 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 23:05:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Now_all_error_?= =?utf-8?q?paths_of_=5Ffreeze=5Fimportlib_use_=27goto_error=27_and_the_err?= =?utf-8?q?or_label?= Message-ID: <3byz4Z5CmzzR1l@mail.python.org> http://hg.python.org/cpython/rev/82706297973b changeset: 84770:82706297973b branch: 3.3 parent: 84768:5607084e2204 user: Christian Heimes date: Sun Jul 21 23:05:04 2013 +0200 summary: Now all error paths of _freeze_importlib use 'goto error' and the error label cleans up all used resources. files: Modules/_freeze_importlib.c | 37 ++++++++++++------------ 1 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Modules/_freeze_importlib.c b/Modules/_freeze_importlib.c --- a/Modules/_freeze_importlib.c +++ b/Modules/_freeze_importlib.c @@ -34,12 +34,12 @@ main(int argc, char *argv[]) { char *inpath, *outpath; - FILE *infile, *outfile = NULL; + FILE *infile = NULL, *outfile = NULL; struct stat st; size_t text_size, data_size, n; - char *text; + char *text = NULL; unsigned char *data; - PyObject *code, *marshalled; + PyObject *code = NULL, *marshalled = NULL; PyImport_FrozenModules = _PyImport_FrozenModules; @@ -52,19 +52,17 @@ infile = fopen(inpath, "rb"); if (infile == NULL) { fprintf(stderr, "cannot open '%s' for reading\n", inpath); - return 1; + goto error; } if (fstat(fileno(infile), &st)) { - fclose(infile); fprintf(stderr, "cannot fstat '%s'\n", inpath); - return 1; + goto error; } text_size = st.st_size; text = (char *) malloc(text_size + 1); if (text == NULL) { - fclose(infile); fprintf(stderr, "could not allocate %ld bytes\n", (long) text_size); - return 1; + goto error; } n = fread(text, 1, text_size, infile); fclose(infile); @@ -72,8 +70,7 @@ if (n < text_size) { fprintf(stderr, "read too short: got %ld instead of %ld bytes\n", (long) n, (long) text_size); - free(text); - return 1; + goto error; } text[text_size] = '\0'; @@ -87,11 +84,13 @@ code = Py_CompileStringExFlags(text, "", Py_file_input, NULL, 0); - free(text); if (code == NULL) goto error; + free(text); + text = NULL; + marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION); - Py_DECREF(code); + Py_CLEAR(code); if (marshalled == NULL) goto error; @@ -104,8 +103,7 @@ outfile = fopen(outpath, "w"); if (outfile == NULL) { fprintf(stderr, "cannot open '%s' for writing\n", outpath); - Py_DECREF(marshalled); - return 1; + goto error; } fprintf(outfile, "%s\n", header); fprintf(outfile, "unsigned char _Py_M__importlib[] = {\n"); @@ -119,16 +117,13 @@ } fprintf(outfile, "};\n"); - Py_DECREF(marshalled); + Py_CLEAR(marshalled); Py_Finalize(); - if (infile) - fclose(infile); if (outfile) { if (ferror(outfile)) { fprintf(stderr, "error when writing to '%s'\n", outpath); - fclose(outfile); - return 1; + goto error; } fclose(outfile); } @@ -141,5 +136,9 @@ fclose(infile); if (outfile) fclose(outfile); + if (text) + free(text); + if (marshalled) + Py_DECREF(marshalled); return 1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 21 23:05:35 2013 From: python-checkins at python.org (christian.heimes) Date: Sun, 21 Jul 2013 23:05:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Now_all_error_paths_of_=5Ffreeze=5Fimportlib_use_=27goto?= =?utf-8?q?_error=27_and_the_error_label?= Message-ID: <3byz4b75HWz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/fe88b7949fbe changeset: 84771:fe88b7949fbe parent: 84769:e82472e4fd97 parent: 84770:82706297973b user: Christian Heimes date: Sun Jul 21 23:05:11 2013 +0200 summary: Now all error paths of _freeze_importlib use 'goto error' and the error label cleans up all used resources. files: Modules/_freeze_importlib.c | 37 ++++++++++++------------ 1 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Modules/_freeze_importlib.c b/Modules/_freeze_importlib.c --- a/Modules/_freeze_importlib.c +++ b/Modules/_freeze_importlib.c @@ -34,12 +34,12 @@ main(int argc, char *argv[]) { char *inpath, *outpath; - FILE *infile, *outfile = NULL; + FILE *infile = NULL, *outfile = NULL; struct stat st; size_t text_size, data_size, n; - char *text; + char *text = NULL; unsigned char *data; - PyObject *code, *marshalled; + PyObject *code = NULL, *marshalled = NULL; PyImport_FrozenModules = _PyImport_FrozenModules; @@ -52,19 +52,17 @@ infile = fopen(inpath, "rb"); if (infile == NULL) { fprintf(stderr, "cannot open '%s' for reading\n", inpath); - return 1; + goto error; } if (fstat(fileno(infile), &st)) { - fclose(infile); fprintf(stderr, "cannot fstat '%s'\n", inpath); - return 1; + goto error; } text_size = st.st_size; text = (char *) malloc(text_size + 1); if (text == NULL) { - fclose(infile); fprintf(stderr, "could not allocate %ld bytes\n", (long) text_size); - return 1; + goto error; } n = fread(text, 1, text_size, infile); fclose(infile); @@ -72,8 +70,7 @@ if (n < text_size) { fprintf(stderr, "read too short: got %ld instead of %ld bytes\n", (long) n, (long) text_size); - free(text); - return 1; + goto error; } text[text_size] = '\0'; @@ -87,11 +84,13 @@ code = Py_CompileStringExFlags(text, "", Py_file_input, NULL, 0); - free(text); if (code == NULL) goto error; + free(text); + text = NULL; + marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION); - Py_DECREF(code); + Py_CLEAR(code); if (marshalled == NULL) goto error; @@ -104,8 +103,7 @@ outfile = fopen(outpath, "w"); if (outfile == NULL) { fprintf(stderr, "cannot open '%s' for writing\n", outpath); - Py_DECREF(marshalled); - return 1; + goto error; } fprintf(outfile, "%s\n", header); fprintf(outfile, "const unsigned char _Py_M__importlib[] = {\n"); @@ -119,16 +117,13 @@ } fprintf(outfile, "};\n"); - Py_DECREF(marshalled); + Py_CLEAR(marshalled); Py_Finalize(); - if (infile) - fclose(infile); if (outfile) { if (ferror(outfile)) { fprintf(stderr, "error when writing to '%s'\n", outpath); - fclose(outfile); - return 1; + goto error; } fclose(outfile); } @@ -141,5 +136,9 @@ fclose(infile); if (outfile) fclose(outfile); + if (text) + free(text); + if (marshalled) + Py_DECREF(marshalled); return 1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 02:13:47 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 22 Jul 2013 02:13:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_Make_test=2Esupport=2Erequires=28=27gui=27=29_skip_when_it_?= =?utf-8?q?should=2E?= Message-ID: <3bz3Fl3m9SzSdZ@mail.python.org> http://hg.python.org/cpython/rev/23b0164b9c82 changeset: 84772:23b0164b9c82 branch: 2.7 parent: 84747:f8df7c50132f user: Terry Jan Reedy date: Sun Jul 21 20:13:24 2013 -0400 summary: Issue #18441: Make test.support.requires('gui') skip when it should. (Consolidating this check and various checks in tkinter files and moving them to test.support and test.regrtest will be another issue.) files: Lib/idlelib/idle_test/test_text.py | 5 +--- Lib/test/test_idle.py | 20 ++++++++++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -216,10 +216,7 @@ requires('gui') from Tkinter import Tk, Text cls.Text = Text - try: - cls.root = Tk() - except TclError as msg: - raise unittest.SkipTest('TclError: %s' % msg) + cls.root = Tk() @classmethod def tearDownClass(cls): 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,9 +1,21 @@ -# Skip test if _tkinter or _thread wasn't built or idlelib was deleted. -from test.test_support import import_module -import_module('Tkinter') -import_module('threading') # imported by PyShell, imports _thread +# Skip test if _thread or _tkinter wasn't built or idlelib was deleted. +from test.test_support import import_module, use_resources +import_module('threading') # imported by idlelib.PyShell, imports _thread +tk = import_module('Tkinter') idletest = import_module('idlelib.idle_test') +# If buildbot improperly sets gui resource (#18365, #18441), remove it +# so requires('gui') tests are skipped while non-gui tests still run. +if use_resources and 'gui' in use_resources: + try: + root = tk.Tk() + root.destroy() + except TclError: + while True: + use_resources.delete('gui') + if 'gui' not in use_resources: + break + # 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.) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 03:14:56 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 22 Jul 2013 03:14:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDM5?= =?utf-8?q?=3A_Make_patchcheck_work_on_Windows_for_ACKS=2C_NEWS=2E?= Message-ID: <3bz4cJ5hRMzP3l@mail.python.org> http://hg.python.org/cpython/rev/26686d227e41 changeset: 84773:26686d227e41 branch: 3.3 parent: 84770:82706297973b user: Terry Jan Reedy date: Sun Jul 21 20:57:44 2013 -0400 summary: Issue #18439: Make patchcheck work on Windows for ACKS, NEWS. files: Misc/NEWS | 2 ++ Tools/scripts/patchcheck.py | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -242,6 +242,8 @@ Tools/Demos ----------- +- Issue #18439: Make patchcheck work on Windows for ACKS, NEWS. + - Issue #18448: Fix a typo in Tools/demo/eiffel.py. - Issue #18457: Fixed saving of formulas and complex numbers in diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py --- a/Tools/scripts/patchcheck.py +++ b/Tools/scripts/patchcheck.py @@ -124,13 +124,13 @@ @status("Misc/ACKS updated", modal=True) def credit_given(file_paths): """Check if Misc/ACKS has been changed.""" - return 'Misc/ACKS' in file_paths + return os.path.join('Misc', 'ACKS') in file_paths @status("Misc/NEWS updated", modal=True) def reported_news(file_paths): """Check if Misc/NEWS has been changed.""" - return 'Misc/NEWS' in file_paths + return os.path.join('Misc', 'NEWS') in file_paths @status("configure regenerated", modal=True, info=str) def regenerated_configure(file_paths): @@ -153,7 +153,8 @@ python_files = [fn for fn in file_paths if fn.endswith('.py')] c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] doc_files = [fn for fn in file_paths if fn.startswith('Doc')] - special_files = {'Misc/ACKS', 'Misc/NEWS'} & set(file_paths) + misc_files = {os.path.join('Misc', 'ACKS'), os.path.join('Misc', 'NEWS')}\ + & set(file_paths) # PEP 8 whitespace rules enforcement. normalize_whitespace(python_files) # C rules enforcement. @@ -163,9 +164,9 @@ # Docs updated. docs_modified(doc_files) # Misc/ACKS changed. - credit_given(special_files) + credit_given(misc_files) # Misc/NEWS changed. - reported_news(special_files) + reported_news(misc_files) # Regenerated configure, if necessary. regenerated_configure(file_paths) # Regenerated pyconfig.h.in, if necessary. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 03:14:58 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 22 Jul 2013 03:14:58 +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: <3bz4cL0Z2hzPns@mail.python.org> http://hg.python.org/cpython/rev/bf9ccd08f559 changeset: 84774:bf9ccd08f559 parent: 84771:fe88b7949fbe parent: 84773:26686d227e41 user: Terry Jan Reedy date: Sun Jul 21 20:58:15 2013 -0400 summary: Merge with 3.3 files: Misc/NEWS | 2 ++ Tools/scripts/patchcheck.py | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -695,6 +695,8 @@ Tools/Demos ----------- +- Issue #18439: Make patchcheck work on Windows for ACKS, NEWS. + - Issue #18448: Fix a typo in Tools/demo/eiffel.py. - Issue #18457: Fixed saving of formulas and complex numbers in diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py --- a/Tools/scripts/patchcheck.py +++ b/Tools/scripts/patchcheck.py @@ -124,13 +124,13 @@ @status("Misc/ACKS updated", modal=True) def credit_given(file_paths): """Check if Misc/ACKS has been changed.""" - return 'Misc/ACKS' in file_paths + return os.path.join('Misc', 'ACKS') in file_paths @status("Misc/NEWS updated", modal=True) def reported_news(file_paths): """Check if Misc/NEWS has been changed.""" - return 'Misc/NEWS' in file_paths + return os.path.join('Misc', 'NEWS') in file_paths @status("configure regenerated", modal=True, info=str) def regenerated_configure(file_paths): @@ -153,7 +153,8 @@ python_files = [fn for fn in file_paths if fn.endswith('.py')] c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] doc_files = [fn for fn in file_paths if fn.startswith('Doc')] - special_files = {'Misc/ACKS', 'Misc/NEWS'} & set(file_paths) + misc_files = {os.path.join('Misc', 'ACKS'), os.path.join('Misc', 'NEWS')}\ + & set(file_paths) # PEP 8 whitespace rules enforcement. normalize_whitespace(python_files) # C rules enforcement. @@ -163,9 +164,9 @@ # Docs updated. docs_modified(doc_files) # Misc/ACKS changed. - credit_given(special_files) + credit_given(misc_files) # Misc/NEWS changed. - reported_news(special_files) + reported_news(misc_files) # Regenerated configure, if necessary. regenerated_configure(file_paths) # Regenerated pyconfig.h.in, if necessary. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 03:14:59 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 22 Jul 2013 03:14:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDM5?= =?utf-8?q?=3A_Make_patchcheck_work_on_Windows_for_ACKS=2C_NEWS=2E?= Message-ID: <3bz4cM2YwSz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/13950a33f889 changeset: 84775:13950a33f889 branch: 2.7 parent: 84772:23b0164b9c82 user: Terry Jan Reedy date: Sun Jul 21 20:57:44 2013 -0400 summary: Issue #18439: Make patchcheck work on Windows for ACKS, NEWS. files: Misc/NEWS | 2 ++ Tools/scripts/patchcheck.py | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -137,6 +137,8 @@ - Issue #17844: Refactor a documentation of Python specific encodings. Add links to encoders and decoders for binary-to-binary codecs. +- Issue #18439: Make patchcheck work on Windows for ACKS, NEWS. + What's New in Python 2.7.5? =========================== diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py --- a/Tools/scripts/patchcheck.py +++ b/Tools/scripts/patchcheck.py @@ -144,13 +144,13 @@ @status("Misc/ACKS updated", modal=True) def credit_given(file_paths): """Check if Misc/ACKS has been changed.""" - return 'Misc/ACKS' in file_paths + return os.path.join('Misc', 'ACKS') in file_paths @status("Misc/NEWS updated", modal=True) def reported_news(file_paths): """Check if Misc/NEWS has been changed.""" - return 'Misc/NEWS' in file_paths + return os.path.join('Misc', 'NEWS') in file_paths def main(): @@ -158,7 +158,8 @@ python_files = [fn for fn in file_paths if fn.endswith('.py')] c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] doc_files = [fn for fn in file_paths if fn.startswith('Doc')] - special_files = {'Misc/ACKS', 'Misc/NEWS'} & set(file_paths) + misc_files = {os.path.join('Misc', 'ACKS'), os.path.join('Misc', 'NEWS')}\ + & set(file_paths) # PEP 8 whitespace rules enforcement. normalize_whitespace(python_files) # C rules enforcement. @@ -168,9 +169,9 @@ # Docs updated. docs_modified(doc_files) # Misc/ACKS changed. - credit_given(special_files) + credit_given(misc_files) # Misc/NEWS changed. - reported_news(special_files) + reported_news(misc_files) # Test suite run and passed. if python_files or c_files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 03:15:00 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 22 Jul 2013 03:15:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDM5?= =?utf-8?q?=3A_Move_news_entry_misplaced_by_graft_merge=2E?= Message-ID: <3bz4cN4VVsz7Ljx@mail.python.org> http://hg.python.org/cpython/rev/f737673e909b changeset: 84776:f737673e909b branch: 2.7 user: Terry Jan Reedy date: Sun Jul 21 21:08:29 2013 -0400 summary: Issue #18439: Move news entry misplaced by graft merge. 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 @@ -80,6 +80,8 @@ Tools/Demos ----------- +- Issue #18439: Make patchcheck work on Windows for ACKS, NEWS. + - Issue #18448: Fix a typo in Demo/newmetaclasses/Eiffel.py. - Issue #12990: The "Python Launcher" on OSX could not launch python scripts @@ -137,8 +139,6 @@ - Issue #17844: Refactor a documentation of Python specific encodings. Add links to encoders and decoders for binary-to-binary codecs. -- Issue #18439: Make patchcheck work on Windows for ACKS, NEWS. - What's New in Python 2.7.5? =========================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 03:25:28 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 22 Jul 2013 03:25:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_fix_buildbot_name-error_for_TclError=2E?= Message-ID: <3bz4rS3vK3zRJ8@mail.python.org> http://hg.python.org/cpython/rev/9f922270a929 changeset: 84777:9f922270a929 branch: 2.7 user: Terry Jan Reedy date: Sun Jul 21 21:24:45 2013 -0400 summary: Issue #18441: fix buildbot name-error for TclError. files: Lib/test/test_idle.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -10,7 +10,7 @@ try: root = tk.Tk() root.destroy() - except TclError: + except tk.TclError: while True: use_resources.delete('gui') if 'gui' not in use_resources: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 03:59:01 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 22 Jul 2013 03:59:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backed_out_cha?= =?utf-8?q?ngeset=3A_9f922270a929_so_can_backout_larger_patch?= Message-ID: <3bz5b96Hj5zNl2@mail.python.org> http://hg.python.org/cpython/rev/08e6a325265c changeset: 84778:08e6a325265c branch: 2.7 user: Terry Jan Reedy date: Sun Jul 21 21:57:02 2013 -0400 summary: Backed out changeset: 9f922270a929 so can backout larger patch files: Lib/test/test_idle.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -10,7 +10,7 @@ try: root = tk.Tk() root.destroy() - except tk.TclError: + except TclError: while True: use_resources.delete('gui') if 'gui' not in use_resources: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 03:59:03 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 22 Jul 2013 03:59:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backed_out_cha?= =?utf-8?q?ngeset=3A_23b0164b9c82_=2318441_not_working?= Message-ID: <3bz5bC0z6gzNl2@mail.python.org> http://hg.python.org/cpython/rev/e8b8279ca118 changeset: 84779:e8b8279ca118 branch: 2.7 user: Terry Jan Reedy date: Sun Jul 21 21:57:52 2013 -0400 summary: Backed out changeset: 23b0164b9c82 #18441 not working files: Lib/idlelib/idle_test/test_text.py | 5 +++- Lib/test/test_idle.py | 20 +++-------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -216,7 +216,10 @@ requires('gui') from Tkinter import Tk, Text cls.Text = Text - cls.root = Tk() + try: + cls.root = Tk() + except TclError as msg: + raise unittest.SkipTest('TclError: %s' % msg) @classmethod def tearDownClass(cls): 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,21 +1,9 @@ -# Skip test if _thread or _tkinter wasn't built or idlelib was deleted. -from test.test_support import import_module, use_resources -import_module('threading') # imported by idlelib.PyShell, imports _thread -tk = import_module('Tkinter') +# Skip test if _tkinter or _thread wasn't built or idlelib was deleted. +from test.test_support import import_module +import_module('Tkinter') +import_module('threading') # imported by PyShell, imports _thread idletest = import_module('idlelib.idle_test') -# If buildbot improperly sets gui resource (#18365, #18441), remove it -# so requires('gui') tests are skipped while non-gui tests still run. -if use_resources and 'gui' in use_resources: - try: - root = tk.Tk() - root.destroy() - except TclError: - while True: - use_resources.delete('gui') - if 'gui' not in use_resources: - break - # 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.) -- Repository URL: http://hg.python.org/cpython From eric at trueblade.com Mon Jul 22 04:05:29 2013 From: eric at trueblade.com (Eric V. Smith) Date: Sun, 21 Jul 2013 22:05:29 -0400 Subject: [Python-checkins] cpython (3.3): let's not return NULL from functions that should return ints In-Reply-To: <3byyDG02GdzQlq@mail.python.org> References: <3byyDG02GdzQlq@mail.python.org> Message-ID: <51EC9369.6000407@trueblade.com> On 7/21/2013 4:27 PM, benjamin.peterson wrote: > @@ -267,7 +267,7 @@ > Py_DECREF(io); > Py_DECREF(binary); > PyMem_FREE(found_encoding); > - return PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, filename); > + return 0; > } > fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding); > Py_DECREF(io); Did you mean to remove the call to PyErr_SetFromErrnoWithFilenameObject? Or just call it, then ignore its return value and return 0? -- Eric. From rdmurray at bitdance.com Mon Jul 22 04:11:42 2013 From: rdmurray at bitdance.com (R. David Murray) Date: Sun, 21 Jul 2013 22:11:42 -0400 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_Make_test=2Esupport=2Erequires=28=27gui=27=29_skip_w?= =?utf-8?q?hen_it_should=2E?= In-Reply-To: <3bz3Fl3m9SzSdZ@mail.python.org> References: <3bz3Fl3m9SzSdZ@mail.python.org> Message-ID: <20130722021142.CC2862500A8@webabinitio.net> On Mon, 22 Jul 2013 02:13:47 +0200, terry.reedy wrote: > +# If buildbot improperly sets gui resource (#18365, #18441), remove it > +# so requires('gui') tests are skipped while non-gui tests still run. > +if use_resources and 'gui' in use_resources: Note that the buildbot cannot "improperly" set the GUI resource. Setting a resource on the regrtest command line says "please try to run these tests". If they can't be run, they should then be skipped for whatever reason they can't run. --David From solipsis at pitrou.net Mon Jul 22 05:52:25 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 22 Jul 2013 05:52:25 +0200 Subject: [Python-checkins] Daily reference leaks (bf9ccd08f559): sum=0 Message-ID: results for bf9ccd08f559 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog7kJQzf', '-x'] From tjreedy at udel.edu Mon Jul 22 06:00:01 2013 From: tjreedy at udel.edu (Terry Reedy) Date: Mon, 22 Jul 2013 00:00:01 -0400 Subject: [Python-checkins] cpython (2.7): Issue #18441: Make test.support.requires('gui') skip when it should. In-Reply-To: <20130722021142.CC2862500A8@webabinitio.net> References: <3bz3Fl3m9SzSdZ@mail.python.org> <20130722021142.CC2862500A8@webabinitio.net> Message-ID: <51ECAE41.5060403@udel.edu> On 7/21/2013 10:11 PM, R. David Murray wrote: > On Mon, 22 Jul 2013 02:13:47 +0200, terry.reedy wrote: >> +# If buildbot improperly sets gui resource (#18365, #18441), remove it >> +# so requires('gui') tests are skipped while non-gui tests still run. >> +if use_resources and 'gui' in use_resources: > > Note that the buildbot cannot "improperly" set the GUI resource. I disagree. I do understand though, that what I call improper setting on the command line cannot be prevented. So I think regrtest (and unittest if and when it supports resources) should intercept 'gui', test once and for all whether it was set 'properly' (or 'appropriately', if you prefer), which is to say, test whether there is a usable GUI, and ignore 'gui' if not. > Setting a resource on the regrtest command line says "please try to run > these tests". When doing so causes a failure at best and a crash at worst, and those consequences and the means of avoiding them are not documented, that is not a very considerate request. It has cost me over a day of my life. The printed out -h help says "gui - Run tests that require a running GUI." Not 'try', but 'run'. That implies to me that there *is* 'a running GUI' and that is it all right to run tests that *require* such. That was also what I understood from the discussion on http://bugs.python.org/issue18103 Create a GUI test framework for Idle What I do not see in the help text or doc is "Warning: 'gui' may be set when trying to run such tests may cause a failure or crash." > If they can't be run, they should then be skipped for > whatever reason they can't run. According to docs and the advice on the issue, including from you, that is to be done with "requires('gui')". Terry From python-checkins at python.org Mon Jul 22 08:35:20 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 22 Jul 2013 08:35:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318488=3A_Fix_=5Fp?= =?utf-8?q?ysqlite=5Ffinal=5Fcallback=28=29?= Message-ID: <3bzCk00NflzShJ@mail.python.org> http://hg.python.org/cpython/rev/020dbfdf9517 changeset: 84780:020dbfdf9517 parent: 84774:bf9ccd08f559 user: Victor Stinner date: Mon Jul 22 08:34:32 2013 +0200 summary: Issue #18488: Fix _pysqlite_final_callback() Restore behaviour of Python 3.3: print the finalizer() error if sqlite3.enable_callback_tracebacks() has been called, clear the error otherwise. But keep (save/restore) also the AttributeError raised in _pysqlite_step_callback(). files: Modules/_sqlite/connection.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -718,10 +718,6 @@ function_result = _PyObject_CallMethodId(*aggregate_instance, &PyId_finalize, ""); - /* Restore the exception (if any) of the last call to step(), - but clear also the current exception if finalize() failed */ - PyErr_Restore(exception, value, tb); - Py_DECREF(*aggregate_instance); ok = 0; @@ -738,6 +734,10 @@ _sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1); } + /* Restore the exception (if any) of the last call to step(), + but clear also the current exception if finalize() failed */ + PyErr_Restore(exception, value, tb); + error: #ifdef WITH_THREAD PyGILState_Release(threadstate); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 10:38:16 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 22 Jul 2013 10:38:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_sanity_che?= =?utf-8?q?ck_to_PyGrammar=5FLabelRepr=28=29_in_order_to_catch_invalid_tok?= =?utf-8?q?ens_when?= Message-ID: <3bzGRr0qlDz7LjS@mail.python.org> http://hg.python.org/cpython/rev/03b937e5b19f changeset: 84781:03b937e5b19f branch: 3.3 parent: 84770:82706297973b user: Christian Heimes date: Mon Jul 22 10:30:14 2013 +0200 summary: Add sanity check to PyGrammar_LabelRepr() in order to catch invalid tokens when debugging a new grammar. CID 715360 files: Parser/grammar1.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Parser/grammar1.c b/Parser/grammar1.c --- a/Parser/grammar1.c +++ b/Parser/grammar1.c @@ -45,7 +45,7 @@ else return lb->lb_str; } - else { + else if (lb->lb_type < N_TOKENS) { if (lb->lb_str == NULL) return _PyParser_TokenNames[lb->lb_type]; else { @@ -54,4 +54,7 @@ return buf; } } + else { + Py_FatalError("invalid label"); + } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 10:38:17 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 22 Jul 2013 10:38:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Add_sanity_check_to_PyGrammar=5FLabelRepr=28=29_in_order?= =?utf-8?q?_to_catch_invalid_tokens_when?= Message-ID: <3bzGRs2rDtz7LjX@mail.python.org> http://hg.python.org/cpython/rev/4f47dd0625bf changeset: 84782:4f47dd0625bf parent: 84780:020dbfdf9517 parent: 84781:03b937e5b19f user: Christian Heimes date: Mon Jul 22 10:30:45 2013 +0200 summary: Add sanity check to PyGrammar_LabelRepr() in order to catch invalid tokens when debugging a new grammar. CID 715360 files: Parser/grammar1.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Parser/grammar1.c b/Parser/grammar1.c --- a/Parser/grammar1.c +++ b/Parser/grammar1.c @@ -45,7 +45,7 @@ else return lb->lb_str; } - else { + else if (lb->lb_type < N_TOKENS) { if (lb->lb_str == NULL) return _PyParser_TokenNames[lb->lb_type]; else { @@ -54,4 +54,7 @@ return buf; } } + else { + Py_FatalError("invalid label"); + } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 10:38:18 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 22 Jul 2013 10:38:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_merge?= Message-ID: <3bzGRt4lNFz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/3cd6858c9f63 changeset: 84783:3cd6858c9f63 branch: 3.3 parent: 84781:03b937e5b19f parent: 84773:26686d227e41 user: Christian Heimes date: Mon Jul 22 10:37:41 2013 +0200 summary: merge files: Misc/NEWS | 2 ++ Tools/scripts/patchcheck.py | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -242,6 +242,8 @@ Tools/Demos ----------- +- Issue #18439: Make patchcheck work on Windows for ACKS, NEWS. + - Issue #18448: Fix a typo in Tools/demo/eiffel.py. - Issue #18457: Fixed saving of formulas and complex numbers in diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py --- a/Tools/scripts/patchcheck.py +++ b/Tools/scripts/patchcheck.py @@ -124,13 +124,13 @@ @status("Misc/ACKS updated", modal=True) def credit_given(file_paths): """Check if Misc/ACKS has been changed.""" - return 'Misc/ACKS' in file_paths + return os.path.join('Misc', 'ACKS') in file_paths @status("Misc/NEWS updated", modal=True) def reported_news(file_paths): """Check if Misc/NEWS has been changed.""" - return 'Misc/NEWS' in file_paths + return os.path.join('Misc', 'NEWS') in file_paths @status("configure regenerated", modal=True, info=str) def regenerated_configure(file_paths): @@ -153,7 +153,8 @@ python_files = [fn for fn in file_paths if fn.endswith('.py')] c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] doc_files = [fn for fn in file_paths if fn.startswith('Doc')] - special_files = {'Misc/ACKS', 'Misc/NEWS'} & set(file_paths) + misc_files = {os.path.join('Misc', 'ACKS'), os.path.join('Misc', 'NEWS')}\ + & set(file_paths) # PEP 8 whitespace rules enforcement. normalize_whitespace(python_files) # C rules enforcement. @@ -163,9 +164,9 @@ # Docs updated. docs_modified(doc_files) # Misc/ACKS changed. - credit_given(special_files) + credit_given(misc_files) # Misc/NEWS changed. - reported_news(special_files) + reported_news(misc_files) # Regenerated configure, if necessary. regenerated_configure(file_paths) # Regenerated pyconfig.h.in, if necessary. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 10:38:19 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 22 Jul 2013 10:38:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bzGRv6clbz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/878dc9dfc565 changeset: 84784:878dc9dfc565 parent: 84782:4f47dd0625bf parent: 84783:3cd6858c9f63 user: Christian Heimes date: Mon Jul 22 10:38:04 2013 +0200 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 12:54:32 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 22 Jul 2013 12:54:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1OTA1?= =?utf-8?q?=3A_Fix_theoretical_buffer_overflow_in_handling_of_sys=2Eargv?= =?utf-8?b?WzBdLA==?= Message-ID: <3bzKT435Lnz7LjY@mail.python.org> http://hg.python.org/cpython/rev/dca92e8a011a changeset: 84785:dca92e8a011a branch: 3.3 parent: 84783:3cd6858c9f63 user: Christian Heimes date: Mon Jul 22 12:53:32 2013 +0200 summary: Issue #15905: Fix theoretical buffer overflow in handling of sys.argv[0], prefix and exec_prefix if the operation system does not obey MAXPATHLEN. files: Misc/NEWS | 3 +++ Modules/getpath.c | 16 ++++++++++++---- Python/sysmodule.c | 7 ++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #15905: Fix theoretical buffer overflow in handling of sys.argv[0], + prefix and exec_prefix if the operation system does not obey MAXPATHLEN. + - Issue #18344: Fix potential ref-leaks in _bufferedreader_read_all(). - Issue #17872: Fix a segfault in marshal.load() when input stream returns diff --git a/Modules/getpath.c b/Modules/getpath.c --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -326,6 +326,7 @@ if (home) { wchar_t *delim; wcsncpy(prefix, home, MAXPATHLEN); + prefix[MAXPATHLEN] = L'\0'; delim = wcschr(prefix, DELIM); if (delim) *delim = L'\0'; @@ -335,13 +336,15 @@ } /* Check to see if argv[0] is in the build directory */ - wcscpy(prefix, argv0_path); + wcsncpy(prefix, argv0_path, MAXPATHLEN); + prefix[MAXPATHLEN] = L'\0'; joinpath(prefix, L"Modules/Setup"); if (isfile(prefix)) { /* Check VPATH to see if argv0_path is in the build directory. */ vpath = _Py_char2wchar(VPATH, NULL); if (vpath != NULL) { - wcscpy(prefix, argv0_path); + wcsncpy(prefix, argv0_path, MAXPATHLEN); + prefix[MAXPATHLEN] = L'\0'; joinpath(prefix, vpath); PyMem_Free(vpath); joinpath(prefix, L"Lib"); @@ -365,6 +368,7 @@ /* Look at configure's PREFIX */ wcsncpy(prefix, _prefix, MAXPATHLEN); + prefix[MAXPATHLEN] = L'\0'; joinpath(prefix, lib_python); joinpath(prefix, LANDMARK); if (ismodule(prefix)) @@ -391,6 +395,7 @@ wcsncpy(exec_prefix, delim+1, MAXPATHLEN); else wcsncpy(exec_prefix, home, MAXPATHLEN); + exec_prefix[MAXPATHLEN] = L'\0'; joinpath(exec_prefix, lib_python); joinpath(exec_prefix, L"lib-dynload"); return 1; @@ -399,7 +404,8 @@ /* Check to see if argv[0] is in the build directory. "pybuilddir.txt" is written by setup.py and contains the relative path to the location of shared library modules. */ - wcscpy(exec_prefix, argv0_path); + wcsncpy(exec_prefix, argv0_path, MAXPATHLEN); + exec_prefix[MAXPATHLEN] = L'\0'; joinpath(exec_prefix, L"pybuilddir.txt"); if (isfile(exec_prefix)) { FILE *f = _Py_wfopen(exec_prefix, L"rb"); @@ -420,7 +426,8 @@ Py_DECREF(decoded); if (k >= 0) { rel_builddir_path[k] = L'\0'; - wcscpy(exec_prefix, argv0_path); + wcsncpy(exec_prefix, argv0_path, MAXPATHLEN); + exec_prefix[MAXPATHLEN] = L'\0'; joinpath(exec_prefix, rel_builddir_path); return -1; } @@ -442,6 +449,7 @@ /* Look at configure's EXEC_PREFIX */ wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN); + exec_prefix[MAXPATHLEN] = L'\0'; joinpath(exec_prefix, lib_python); joinpath(exec_prefix, L"lib-dynload"); if (isdir(exec_prefix)) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1856,10 +1856,11 @@ if (q == NULL) argv0 = link; /* argv0 without path */ else { - /* Must make a copy */ - wcscpy(argv0copy, argv0); + /* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */ + wcsncpy(argv0copy, argv0, MAXPATHLEN); q = wcsrchr(argv0copy, SEP); - wcscpy(q+1, link); + wcsncpy(q+1, link, MAXPATHLEN); + q[MAXPATHLEN + 1] = L'\0'; argv0 = argv0copy; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 12:54:33 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 22 Jul 2013 12:54:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315905=3A_Fix_theoretical_buffer_overflow_in_han?= =?utf-8?b?ZGxpbmcgb2Ygc3lzLmFyZ3ZbMF0s?= Message-ID: <3bzKT56Hk7z7LkN@mail.python.org> http://hg.python.org/cpython/rev/01597384531f changeset: 84786:01597384531f parent: 84784:878dc9dfc565 parent: 84785:dca92e8a011a user: Christian Heimes date: Mon Jul 22 12:54:21 2013 +0200 summary: Issue #15905: Fix theoretical buffer overflow in handling of sys.argv[0], prefix and exec_prefix if the operation system does not obey MAXPATHLEN. files: Misc/NEWS | 3 +++ Modules/getpath.c | 16 ++++++++++++---- Python/sysmodule.c | 7 ++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15905: Fix theoretical buffer overflow in handling of sys.argv[0], + prefix and exec_prefix if the operation system does not obey MAXPATHLEN. + - Issue #18408: Fix many various bugs in code handling errors, especially on memory allocation failure (MemoryError). diff --git a/Modules/getpath.c b/Modules/getpath.c --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -326,6 +326,7 @@ if (home) { wchar_t *delim; wcsncpy(prefix, home, MAXPATHLEN); + prefix[MAXPATHLEN] = L'\0'; delim = wcschr(prefix, DELIM); if (delim) *delim = L'\0'; @@ -335,13 +336,15 @@ } /* Check to see if argv[0] is in the build directory */ - wcscpy(prefix, argv0_path); + wcsncpy(prefix, argv0_path, MAXPATHLEN); + prefix[MAXPATHLEN] = L'\0'; joinpath(prefix, L"Modules/Setup"); if (isfile(prefix)) { /* Check VPATH to see if argv0_path is in the build directory. */ vpath = _Py_char2wchar(VPATH, NULL); if (vpath != NULL) { - wcscpy(prefix, argv0_path); + wcsncpy(prefix, argv0_path, MAXPATHLEN); + prefix[MAXPATHLEN] = L'\0'; joinpath(prefix, vpath); PyMem_RawFree(vpath); joinpath(prefix, L"Lib"); @@ -365,6 +368,7 @@ /* Look at configure's PREFIX */ wcsncpy(prefix, _prefix, MAXPATHLEN); + prefix[MAXPATHLEN] = L'\0'; joinpath(prefix, lib_python); joinpath(prefix, LANDMARK); if (ismodule(prefix)) @@ -391,6 +395,7 @@ wcsncpy(exec_prefix, delim+1, MAXPATHLEN); else wcsncpy(exec_prefix, home, MAXPATHLEN); + exec_prefix[MAXPATHLEN] = L'\0'; joinpath(exec_prefix, lib_python); joinpath(exec_prefix, L"lib-dynload"); return 1; @@ -399,7 +404,8 @@ /* Check to see if argv[0] is in the build directory. "pybuilddir.txt" is written by setup.py and contains the relative path to the location of shared library modules. */ - wcscpy(exec_prefix, argv0_path); + wcsncpy(exec_prefix, argv0_path, MAXPATHLEN); + exec_prefix[MAXPATHLEN] = L'\0'; joinpath(exec_prefix, L"pybuilddir.txt"); if (isfile(exec_prefix)) { FILE *f = _Py_wfopen(exec_prefix, L"rb"); @@ -420,7 +426,8 @@ Py_DECREF(decoded); if (k >= 0) { rel_builddir_path[k] = L'\0'; - wcscpy(exec_prefix, argv0_path); + wcsncpy(exec_prefix, argv0_path, MAXPATHLEN); + exec_prefix[MAXPATHLEN] = L'\0'; joinpath(exec_prefix, rel_builddir_path); return -1; } @@ -442,6 +449,7 @@ /* Look at configure's EXEC_PREFIX */ wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN); + exec_prefix[MAXPATHLEN] = L'\0'; joinpath(exec_prefix, lib_python); joinpath(exec_prefix, L"lib-dynload"); if (isdir(exec_prefix)) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1854,10 +1854,11 @@ if (q == NULL) argv0 = link; /* argv0 without path */ else { - /* Must make a copy */ - wcscpy(argv0copy, argv0); + /* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */ + wcsncpy(argv0copy, argv0, MAXPATHLEN); q = wcsrchr(argv0copy, SEP); - wcscpy(q+1, link); + wcsncpy(q+1, link, MAXPATHLEN); + q[MAXPATHLEN + 1] = L'\0'; argv0 = argv0copy; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 16:34:40 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 22 Jul 2013 16:34:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Some_compilers?= =?utf-8?q?_complain_about_=27control_reaches_end_of_non-void_function=27?= Message-ID: <3bzQM42LGPz7Lkd@mail.python.org> http://hg.python.org/cpython/rev/b78f84bb1eeb changeset: 84787:b78f84bb1eeb branch: 3.3 parent: 84785:dca92e8a011a user: Christian Heimes date: Mon Jul 22 16:34:13 2013 +0200 summary: Some compilers complain about 'control reaches end of non-void function' because they don't understand that Py_FatalError() terminates the program. files: Parser/grammar1.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Parser/grammar1.c b/Parser/grammar1.c --- a/Parser/grammar1.c +++ b/Parser/grammar1.c @@ -56,5 +56,6 @@ } else { Py_FatalError("invalid label"); + return NULL; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 16:34:41 2013 From: python-checkins at python.org (christian.heimes) Date: Mon, 22 Jul 2013 16:34:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Some_compilers_complain_about_=27control_reaches_end_of_?= =?utf-8?q?non-void_function=27?= Message-ID: <3bzQM54NX8zLvC@mail.python.org> http://hg.python.org/cpython/rev/84d6c1c0665e changeset: 84788:84d6c1c0665e parent: 84786:01597384531f parent: 84787:b78f84bb1eeb user: Christian Heimes date: Mon Jul 22 16:34:28 2013 +0200 summary: Some compilers complain about 'control reaches end of non-void function' because they don't understand that Py_FatalError() terminates the program. files: Parser/grammar1.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Parser/grammar1.c b/Parser/grammar1.c --- a/Parser/grammar1.c +++ b/Parser/grammar1.c @@ -56,5 +56,6 @@ } else { Py_FatalError("invalid label"); + return NULL; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 20:04:25 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 22 Jul 2013 20:04:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3OTQ0?= =?utf-8?q?=3A_test=5Fzipfile_now_discoverable_and_uses_subclassing_to?= Message-ID: <3bzW151Yfsz7LkB@mail.python.org> http://hg.python.org/cpython/rev/bb63f813a00f changeset: 84789:bb63f813a00f branch: 3.3 parent: 84787:b78f84bb1eeb user: Serhiy Storchaka date: Mon Jul 22 21:00:11 2013 +0300 summary: Issue #17944: test_zipfile now discoverable and uses subclassing to generate tests for different compression types. Fixed a bug with skipping some tests due to use of exhausted iterators. files: Lib/test/test_zipfile.py | 1445 ++++++++++--------------- Misc/NEWS | 4 + 2 files changed, 583 insertions(+), 866 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 @@ -10,10 +10,9 @@ from tempfile import TemporaryFile -from random import randint, random -from unittest import skipUnless +from random import randint, random, getrandbits -from test.support import (TESTFN, run_unittest, findfile, unlink, +from test.support import (TESTFN, findfile, unlink, requires_zlib, requires_bz2, requires_lzma, captured_stdout) @@ -27,14 +26,24 @@ ('ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'), ('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3', '6y7u8i9o0p')] +def get_files(test): + yield TESTFN2 + with TemporaryFile() as f: + yield f + test.assertFalse(f.closed) + with io.BytesIO() as f: + yield f + test.assertFalse(f.closed) -class TestsWithSourceFile(unittest.TestCase): +class AbstractTestsWithSourceFile: + @classmethod + def setUpClass(cls): + cls.line_gen = [bytes("Zipfile test line %d. random float: %f\n" % + (i, random()), "ascii") + for i in range(FIXEDTEST_SIZE)] + cls.data = b''.join(cls.line_gen) + def setUp(self): - self.line_gen = (bytes("Zipfile test line %d. random float: %f" % - (i, random()), "ascii") - for i in range(FIXEDTEST_SIZE)) - self.data = b'\n'.join(self.line_gen) + b'\n' - # Make a source file with some lines with open(TESTFN, "wb") as fp: fp.write(self.data) @@ -97,12 +106,10 @@ # Check that testzip doesn't raise an exception zipfp.testzip() - if not isinstance(f, str): - f.close() - def test_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_STORED) + def test_basic(self): + for f in get_files(self): + self.zip_test(f, self.compression) def zip_open_test(self, f, compression): self.make_test_archive(f, compression) @@ -127,30 +134,10 @@ self.assertEqual(b''.join(zipdata1), self.data) self.assertEqual(b''.join(zipdata2), self.data) - if not isinstance(f, str): - f.close() - def test_open_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_STORED) - - def test_open_via_zip_info(self): - # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: - zipfp.writestr("name", "foo") - zipfp.writestr("name", "bar") - - with zipfile.ZipFile(TESTFN2, "r") as zipfp: - infos = zipfp.infolist() - data = b"" - for info in infos: - with zipfp.open(info) as zipopen: - data += zipopen.read() - self.assertTrue(data == b"foobar" or data == b"barfoo") - data = b"" - for info in infos: - data += zipfp.read(info) - self.assertTrue(data == b"foobar" or data == b"barfoo") + def test_open(self): + for f in get_files(self): + self.zip_open_test(f, self.compression) def zip_random_open_test(self, f, compression): self.make_test_archive(f, compression) @@ -166,36 +153,17 @@ zipdata1.append(read_data) self.assertEqual(b''.join(zipdata1), self.data) - if not isinstance(f, str): - f.close() - def test_random_open_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_STORED) - - def test_univeral_readaheads(self): - f = io.BytesIO() - - data = b'a\r\n' * 16 * 1024 - zipfp = zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) - zipfp.writestr(TESTFN, data) - zipfp.close() - - data2 = b'' - zipfp = zipfile.ZipFile(f, 'r') - with zipfp.open(TESTFN, 'rU') as zipopen: - for line in zipopen: - data2 += line - zipfp.close() - - self.assertEqual(data, data2.replace(b'\n', b'\r\n')) + def test_random_open(self): + for f in get_files(self): + self.zip_random_open_test(f, self.compression) def zip_readline_read_test(self, f, compression): self.make_test_archive(f, compression) # Read the ZIP archive - zipfp = zipfile.ZipFile(f, "r") - with zipfp.open(TESTFN) as zipopen: + with zipfile.ZipFile(f, "r") as zipfp, \ + zipfp.open(TESTFN) as zipopen: data = b'' while True: read = zipopen.readline() @@ -209,9 +177,11 @@ data += read self.assertEqual(data, self.data) - zipfp.close() - if not isinstance(f, str): - f.close() + + def test_readline_read(self): + # Issue #7610: calls to readline() interleaved with calls to read(). + for f in get_files(self): + self.zip_readline_read_test(f, self.compression) def zip_readline_test(self, f, compression): self.make_test_archive(f, compression) @@ -221,9 +191,11 @@ with zipfp.open(TESTFN) as zipopen: for line in self.line_gen: linedata = zipopen.readline() - self.assertEqual(linedata, line + '\n') - if not isinstance(f, str): - f.close() + self.assertEqual(linedata, line) + + def test_readline(self): + for f in get_files(self): + self.zip_readline_test(f, self.compression) def zip_readlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -233,9 +205,11 @@ with zipfp.open(TESTFN) as zipopen: ziplines = zipopen.readlines() for line, zipline in zip(self.line_gen, ziplines): - self.assertEqual(zipline, line + '\n') - if not isinstance(f, str): - f.close() + self.assertEqual(zipline, line) + + def test_readlines(self): + for f in get_files(self): + self.zip_readlines_test(f, self.compression) def zip_iterlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -244,173 +218,64 @@ with zipfile.ZipFile(f, "r") as zipfp: with zipfp.open(TESTFN) as zipopen: for line, zipline in zip(self.line_gen, zipopen): - self.assertEqual(zipline, line + '\n') - if not isinstance(f, str): - f.close() + self.assertEqual(zipline, line) - def test_readline_read_stored(self): - # Issue #7610: calls to readline() interleaved with calls to read(). - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_STORED) + def test_iterlines(self): + for f in get_files(self): + self.zip_iterlines_test(f, self.compression) - def test_readline_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_STORED) - - def test_readlines_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_STORED) - - def test_iterlines_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_STORED) - - @requires_zlib - def test_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_DEFLATED) - - - @requires_zlib - def test_open_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_random_open_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_readline_read_deflated(self): - # Issue #7610: calls to readline() interleaved with calls to read(). - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_readline_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_readlines_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_iterlines_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib def test_low_compression(self): """Check for cases where compressed data is larger than original.""" # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp: + with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipfp: zipfp.writestr("strfile", '12') # Get an open object for strfile - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp: + with zipfile.ZipFile(TESTFN2, "r", self.compression) as zipfp: with zipfp.open("strfile") as openobj: self.assertEqual(openobj.read(1), b'1') self.assertEqual(openobj.read(1), b'2') - @requires_bz2 - def test_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_BZIP2) + def test_writestr_compression(self): + zipfp = zipfile.ZipFile(TESTFN2, "w") + zipfp.writestr("b.txt", "hello world", compress_type=self.compression) + info = zipfp.getinfo('b.txt') + self.assertEqual(info.compress_type, self.compression) - @requires_bz2 - def test_open_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_BZIP2) + def test_read_return_size(self): + # Issue #9837: ZipExtFile.read() shouldn't return more bytes + # than requested. + for test_size in (1, 4095, 4096, 4097, 16384): + file_size = test_size + 1 + junk = getrandbits(8 * file_size).to_bytes(file_size, 'little') + with zipfile.ZipFile(io.BytesIO(), "w", self.compression) as zipf: + zipf.writestr('foo', junk) + with zipf.open('foo', 'r') as fp: + buf = fp.read(test_size) + self.assertEqual(len(buf), test_size) - @requires_bz2 - def test_random_open_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_BZIP2) + def tearDown(self): + unlink(TESTFN) + unlink(TESTFN2) - @requires_bz2 - def test_readline_read_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_BZIP2) - @requires_bz2 - def test_readline_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_BZIP2) +class StoredTestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_STORED + test_low_compression = None - @requires_bz2 - def test_readlines_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_BZIP2) + def zip_test_writestr_permissions(self, f, compression): + # Make sure that writestr creates files with mode 0600, + # when it is passed a name rather than a ZipInfo instance. - @requires_bz2 - def test_iterlines_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_BZIP2) + self.make_test_archive(f, compression) + with zipfile.ZipFile(f, "r") as zipfp: + zinfo = zipfp.getinfo('strfile') + self.assertEqual(zinfo.external_attr, 0o600 << 16) - @requires_bz2 - def test_low_compression_bzip2(self): - """Check for cases where compressed data is larger than original.""" - # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_BZIP2) as zipfp: - zipfp.writestr("strfile", '12') - - # Get an open object for strfile - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_BZIP2) as zipfp: - with zipfp.open("strfile") as openobj: - self.assertEqual(openobj.read(1), b'1') - self.assertEqual(openobj.read(1), b'2') - - @requires_lzma - def test_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_open_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_random_open_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_readline_read_lzma(self): - # Issue #7610: calls to readline() interleaved with calls to read(). - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_readline_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_readlines_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_iterlines_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_low_compression_lzma(self): - """Check for cases where compressed data is larger than original.""" - # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_LZMA) as zipfp: - zipfp.writestr("strfile", '12') - - # Get an open object for strfile - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_LZMA) as zipfp: - with zipfp.open("strfile") as openobj: - self.assertEqual(openobj.read(1), b'1') - self.assertEqual(openobj.read(1), b'2') + def test_writestr_permissions(self): + for f in get_files(self): + self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED) def test_absolute_arcnames(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: @@ -470,7 +335,26 @@ with open(TESTFN, "rb") as f: self.assertEqual(zipfp.read(TESTFN), f.read()) - @requires_zlib + def test_write_to_readonly(self): + """Check that trying to call write() on a readonly ZipFile object + raises a RuntimeError.""" + with zipfile.ZipFile(TESTFN2, mode="w") as zipfp: + zipfp.writestr("somefile.txt", "bogus") + + with zipfile.ZipFile(TESTFN2, mode="r") as zipfp: + self.assertRaises(RuntimeError, zipfp.write, TESTFN) + + def test_add_file_before_1980(self): + # Set atime and mtime to 1970-01-01 + os.utime(TESTFN, (0, 0)) + with zipfile.ZipFile(TESTFN2, "w") as zipfp: + self.assertRaises(ValueError, zipfp.write, TESTFN) + + at requires_zlib +class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_DEFLATED + def test_per_file_compression(self): """Check that files within a Zip archive can have different compression options.""" @@ -482,15 +366,263 @@ self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED) self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED) - def test_write_to_readonly(self): - """Check that trying to call write() on a readonly ZipFile object - raises a RuntimeError.""" - with zipfile.ZipFile(TESTFN2, mode="w") as zipfp: - zipfp.writestr("somefile.txt", "bogus") + at requires_bz2 +class Bzip2TestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_BZIP2 - with zipfile.ZipFile(TESTFN2, mode="r") as zipfp: - self.assertRaises(RuntimeError, zipfp.write, TESTFN) + at requires_lzma +class LzmaTestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_LZMA + +class AbstractTestZip64InSmallFiles: + # These tests test the ZIP64 functionality without using large files, + # see test_zipfile64 for proper tests. + + @classmethod + def setUpClass(cls): + line_gen = (bytes("Test of zipfile line %d." % i, "ascii") + for i in range(0, FIXEDTEST_SIZE)) + cls.data = b'\n'.join(line_gen) + + def setUp(self): + self._limit = zipfile.ZIP64_LIMIT + zipfile.ZIP64_LIMIT = 5 + + # Make a source file with some lines + with open(TESTFN, "wb") as fp: + fp.write(self.data) + + def zip_test(self, f, compression): + # Create the ZIP archive + with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp: + zipfp.write(TESTFN, "another.name") + zipfp.write(TESTFN, TESTFN) + zipfp.writestr("strfile", self.data) + + # Read the ZIP archive + with zipfile.ZipFile(f, "r", compression) as zipfp: + self.assertEqual(zipfp.read(TESTFN), self.data) + self.assertEqual(zipfp.read("another.name"), self.data) + self.assertEqual(zipfp.read("strfile"), self.data) + + # Print the ZIP directory + fp = io.StringIO() + zipfp.printdir(fp) + + directory = fp.getvalue() + lines = directory.splitlines() + self.assertEqual(len(lines), 4) # Number of files + header + + self.assertIn('File Name', lines[0]) + self.assertIn('Modified', lines[0]) + self.assertIn('Size', lines[0]) + + fn, date, time_, size = lines[1].split() + self.assertEqual(fn, 'another.name') + self.assertTrue(time.strptime(date, '%Y-%m-%d')) + self.assertTrue(time.strptime(time_, '%H:%M:%S')) + self.assertEqual(size, str(len(self.data))) + + # Check the namelist + names = zipfp.namelist() + self.assertEqual(len(names), 3) + self.assertIn(TESTFN, names) + self.assertIn("another.name", names) + self.assertIn("strfile", names) + + # Check infolist + infos = zipfp.infolist() + names = [i.filename for i in infos] + self.assertEqual(len(names), 3) + self.assertIn(TESTFN, names) + self.assertIn("another.name", names) + self.assertIn("strfile", names) + for i in infos: + self.assertEqual(i.file_size, len(self.data)) + + # check getinfo + for nm in (TESTFN, "another.name", "strfile"): + info = zipfp.getinfo(nm) + self.assertEqual(info.filename, nm) + self.assertEqual(info.file_size, len(self.data)) + + # Check that testzip doesn't raise an exception + zipfp.testzip() + + def test_basic(self): + for f in get_files(self): + self.zip_test(f, self.compression) + + def tearDown(self): + zipfile.ZIP64_LIMIT = self._limit + unlink(TESTFN) + unlink(TESTFN2) + + +class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_STORED + + def large_file_exception_test(self, f, compression): + with zipfile.ZipFile(f, "w", compression) as zipfp: + self.assertRaises(zipfile.LargeZipFile, + zipfp.write, TESTFN, "another.name") + + def large_file_exception_test2(self, f, compression): + with zipfile.ZipFile(f, "w", compression) as zipfp: + self.assertRaises(zipfile.LargeZipFile, + zipfp.writestr, "another.name", self.data) + + def test_large_file_exception(self): + for f in get_files(self): + self.large_file_exception_test(f, zipfile.ZIP_STORED) + self.large_file_exception_test2(f, zipfile.ZIP_STORED) + + def test_absolute_arcnames(self): + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, + allowZip64=True) as zipfp: + zipfp.write(TESTFN, "/absolute") + + with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp: + self.assertEqual(zipfp.namelist(), ["absolute"]) + + at requires_zlib +class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_DEFLATED + + at requires_bz2 +class Bzip2TestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_BZIP2 + + at requires_lzma +class LzmaTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_LZMA + + +class PyZipFileTests(unittest.TestCase): + def assertCompiledIn(self, name, namelist): + if name + 'o' not in namelist: + self.assertIn(name + 'c', namelist) + + def test_write_pyfile(self): + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + fn = __file__ + if fn.endswith('.pyc') or fn.endswith('.pyo'): + path_split = fn.split(os.sep) + if os.altsep is not None: + path_split.extend(fn.split(os.altsep)) + if '__pycache__' in path_split: + fn = imp.source_from_cache(fn) + else: + fn = fn[:-1] + + zipfp.writepy(fn) + + bn = os.path.basename(fn) + self.assertNotIn(bn, zipfp.namelist()) + self.assertCompiledIn(bn, zipfp.namelist()) + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + fn = __file__ + if fn.endswith(('.pyc', '.pyo')): + fn = fn[:-1] + + zipfp.writepy(fn, "testpackage") + + bn = "%s/%s" % ("testpackage", os.path.basename(fn)) + self.assertNotIn(bn, zipfp.namelist()) + self.assertCompiledIn(bn, zipfp.namelist()) + + def test_write_python_package(self): + import email + packagedir = os.path.dirname(email.__file__) + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + zipfp.writepy(packagedir) + + # Check for a couple of modules at different levels of the + # hierarchy + names = zipfp.namelist() + self.assertCompiledIn('email/__init__.py', names) + self.assertCompiledIn('email/mime/text.py', names) + + def test_write_with_optimization(self): + import email + packagedir = os.path.dirname(email.__file__) + # use .pyc if running test in optimization mode, + # use .pyo if running test in debug mode + optlevel = 1 if __debug__ else 0 + ext = '.pyo' if optlevel == 1 else '.pyc' + + with TemporaryFile() as t, \ + zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp: + zipfp.writepy(packagedir) + + names = zipfp.namelist() + self.assertIn('email/__init__' + ext, names) + self.assertIn('email/mime/text' + ext, names) + + def test_write_python_directory(self): + os.mkdir(TESTFN2) + try: + with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: + fp.write("print(42)\n") + + with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp: + fp.write("print(42 * 42)\n") + + with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp: + fp.write("bla bla bla\n") + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + zipfp.writepy(TESTFN2) + + names = zipfp.namelist() + self.assertCompiledIn('mod1.py', names) + self.assertCompiledIn('mod2.py', names) + self.assertNotIn('mod2.txt', names) + + finally: + shutil.rmtree(TESTFN2) + + def test_write_non_pyfile(self): + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + with open(TESTFN, 'w') as f: + f.write('most definitely not a python file') + self.assertRaises(RuntimeError, zipfp.writepy, TESTFN) + os.remove(TESTFN) + + def test_write_pyfile_bad_syntax(self): + os.mkdir(TESTFN2) + try: + with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: + fp.write("Bad syntax in python file\n") + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + # syntax errors are printed to stdout + with captured_stdout() as s: + zipfp.writepy(os.path.join(TESTFN2, "mod1.py")) + + self.assertIn("SyntaxError", s.getvalue()) + + # as it will not have compiled the python file, it will + # include the .py file not .pyc or .pyo + names = zipfp.namelist() + self.assertIn('mod1.py', names) + self.assertNotIn('mod1.pyc', names) + self.assertNotIn('mod1.pyo', names) + + finally: + shutil.rmtree(TESTFN2) + + +class ExtractTests(unittest.TestCase): def test_extract(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: for fpath, fdata in SMALL_TEST_DATA: @@ -636,47 +768,40 @@ os.remove(TESTFN2) - def test_writestr_compression_stored(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("a.txt", "hello world", compress_type=zipfile.ZIP_STORED) - info = zipfp.getinfo('a.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_STORED) - @requires_zlib - def test_writestr_compression_deflated(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_DEFLATED) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_DEFLATED) +class OtherTests(unittest.TestCase): + def test_open_via_zip_info(self): + # Create the ZIP archive + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: + zipfp.writestr("name", "foo") + zipfp.writestr("name", "bar") - @requires_bz2 - def test_writestr_compression_bzip2(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_BZIP2) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_BZIP2) + with zipfile.ZipFile(TESTFN2, "r") as zipfp: + infos = zipfp.infolist() + data = b"" + for info in infos: + with zipfp.open(info) as zipopen: + data += zipopen.read() + self.assertIn(data, {b"foobar", b"barfoo"}) + data = b"" + for info in infos: + data += zipfp.read(info) + self.assertIn(data, {b"foobar", b"barfoo"}) - @requires_lzma - def test_writestr_compression_lzma(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_LZMA) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_LZMA) + def test_universal_readaheads(self): + f = io.BytesIO() - def zip_test_writestr_permissions(self, f, compression): - # Make sure that writestr creates files with mode 0600, - # when it is passed a name rather than a ZipInfo instance. + data = b'a\r\n' * 16 * 1024 + with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.writestr(TESTFN, data) - self.make_test_archive(f, compression) - with zipfile.ZipFile(f, "r") as zipfp: - zinfo = zipfp.getinfo('strfile') - self.assertEqual(zinfo.external_attr, 0o600 << 16) - if not isinstance(f, str): - f.close() + data2 = b'' + with zipfile.ZipFile(f, 'r') as zipfp, \ + zipfp.open(TESTFN, 'rU') as zipopen: + for line in zipopen: + data2 += line - def test_writestr_permissions(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED) + self.assertEqual(data, data2.replace(b'\n', b'\r\n')) def test_writestr_extended_local_header_issue1202(self): with zipfile.ZipFile(TESTFN2, 'w') as orig_zip: @@ -690,12 +815,12 @@ with zipfile.ZipFile(TESTFN2, "w") as zipfp: for fpath, fdata in SMALL_TEST_DATA: zipfp.writestr(fpath, fdata) - self.assertTrue(zipfp.fp is not None, 'zipfp is not open') - self.assertTrue(zipfp.fp is None, 'zipfp is not closed') + self.assertIsNotNone(zipfp.fp, 'zipfp is not open') + self.assertIsNone(zipfp.fp, 'zipfp is not closed') with zipfile.ZipFile(TESTFN2, "r") as zipfp: - self.assertTrue(zipfp.fp is not None, 'zipfp is not open') - self.assertTrue(zipfp.fp is None, 'zipfp is not closed') + self.assertIsNotNone(zipfp.fp, 'zipfp is not open') + self.assertIsNone(zipfp.fp, 'zipfp is not closed') def test_close_on_exception(self): """Check that the zipfile is closed if an exception is raised in the @@ -708,317 +833,7 @@ with zipfile.ZipFile(TESTFN2, "r") as zipfp2: raise zipfile.BadZipFile() except zipfile.BadZipFile: - self.assertTrue(zipfp2.fp is None, 'zipfp is not closed') - - def test_add_file_before_1980(self): - # Set atime and mtime to 1970-01-01 - os.utime(TESTFN, (0, 0)) - with zipfile.ZipFile(TESTFN2, "w") as zipfp: - self.assertRaises(ValueError, zipfp.write, TESTFN) - - - - - - - - @requires_zlib - def test_unicode_filenames(self): - # bug #10801 - fname = findfile('zip_cp437_header.zip') - with zipfile.ZipFile(fname) as zipfp: - for name in zipfp.namelist(): - zipfp.open(name).close() - - def tearDown(self): - unlink(TESTFN) - unlink(TESTFN2) - - -class TestZip64InSmallFiles(unittest.TestCase): - # These tests test the ZIP64 functionality without using large files, - # see test_zipfile64 for proper tests. - - def setUp(self): - self._limit = zipfile.ZIP64_LIMIT - zipfile.ZIP64_LIMIT = 5 - - line_gen = (bytes("Test of zipfile line %d." % i, "ascii") - for i in range(0, FIXEDTEST_SIZE)) - self.data = b'\n'.join(line_gen) - - # Make a source file with some lines - with open(TESTFN, "wb") as fp: - fp.write(self.data) - - def large_file_exception_test(self, f, compression): - with zipfile.ZipFile(f, "w", compression) as zipfp: - self.assertRaises(zipfile.LargeZipFile, - zipfp.write, TESTFN, "another.name") - - def large_file_exception_test2(self, f, compression): - with zipfile.ZipFile(f, "w", compression) as zipfp: - self.assertRaises(zipfile.LargeZipFile, - zipfp.writestr, "another.name", self.data) - if not isinstance(f, str): - f.close() - - def test_large_file_exception(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.large_file_exception_test(f, zipfile.ZIP_STORED) - self.large_file_exception_test2(f, zipfile.ZIP_STORED) - - def zip_test(self, f, compression): - # Create the ZIP archive - with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp: - zipfp.write(TESTFN, "another.name") - zipfp.write(TESTFN, TESTFN) - zipfp.writestr("strfile", self.data) - - # Read the ZIP archive - with zipfile.ZipFile(f, "r", compression) as zipfp: - self.assertEqual(zipfp.read(TESTFN), self.data) - self.assertEqual(zipfp.read("another.name"), self.data) - self.assertEqual(zipfp.read("strfile"), self.data) - - # Print the ZIP directory - fp = io.StringIO() - zipfp.printdir(fp) - - directory = fp.getvalue() - lines = directory.splitlines() - self.assertEqual(len(lines), 4) # Number of files + header - - self.assertIn('File Name', lines[0]) - self.assertIn('Modified', lines[0]) - self.assertIn('Size', lines[0]) - - fn, date, time_, size = lines[1].split() - self.assertEqual(fn, 'another.name') - self.assertTrue(time.strptime(date, '%Y-%m-%d')) - self.assertTrue(time.strptime(time_, '%H:%M:%S')) - self.assertEqual(size, str(len(self.data))) - - # Check the namelist - names = zipfp.namelist() - self.assertEqual(len(names), 3) - self.assertIn(TESTFN, names) - self.assertIn("another.name", names) - self.assertIn("strfile", names) - - # Check infolist - infos = zipfp.infolist() - names = [i.filename for i in infos] - self.assertEqual(len(names), 3) - self.assertIn(TESTFN, names) - self.assertIn("another.name", names) - self.assertIn("strfile", names) - for i in infos: - self.assertEqual(i.file_size, len(self.data)) - - # check getinfo - for nm in (TESTFN, "another.name", "strfile"): - info = zipfp.getinfo(nm) - self.assertEqual(info.filename, nm) - self.assertEqual(info.file_size, len(self.data)) - - # Check that testzip doesn't raise an exception - zipfp.testzip() - if not isinstance(f, str): - f.close() - - def test_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_STORED) - - @requires_zlib - def test_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_BZIP2) - - @requires_lzma - def test_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_LZMA) - - def test_absolute_arcnames(self): - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, - allowZip64=True) as zipfp: - zipfp.write(TESTFN, "/absolute") - - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp: - self.assertEqual(zipfp.namelist(), ["absolute"]) - - def tearDown(self): - zipfile.ZIP64_LIMIT = self._limit - unlink(TESTFN) - unlink(TESTFN2) - - -class PyZipFileTests(unittest.TestCase): - def test_write_pyfile(self): - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - fn = __file__ - if fn.endswith('.pyc') or fn.endswith('.pyo'): - path_split = fn.split(os.sep) - if os.altsep is not None: - path_split.extend(fn.split(os.altsep)) - if '__pycache__' in path_split: - fn = imp.source_from_cache(fn) - else: - fn = fn[:-1] - - zipfp.writepy(fn) - - bn = os.path.basename(fn) - self.assertNotIn(bn, zipfp.namelist()) - self.assertTrue(bn + 'o' in zipfp.namelist() or - bn + 'c' in zipfp.namelist()) - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - fn = __file__ - if fn.endswith(('.pyc', '.pyo')): - fn = fn[:-1] - - zipfp.writepy(fn, "testpackage") - - bn = "%s/%s" % ("testpackage", os.path.basename(fn)) - self.assertNotIn(bn, zipfp.namelist()) - self.assertTrue(bn + 'o' in zipfp.namelist() or - bn + 'c' in zipfp.namelist()) - - def test_write_python_package(self): - import email - packagedir = os.path.dirname(email.__file__) - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - zipfp.writepy(packagedir) - - # Check for a couple of modules at different levels of the - # hierarchy - names = zipfp.namelist() - self.assertTrue('email/__init__.pyo' in names or - 'email/__init__.pyc' in names) - self.assertTrue('email/mime/text.pyo' in names or - 'email/mime/text.pyc' in names) - - def test_write_with_optimization(self): - import email - packagedir = os.path.dirname(email.__file__) - # use .pyc if running test in optimization mode, - # use .pyo if running test in debug mode - optlevel = 1 if __debug__ else 0 - ext = '.pyo' if optlevel == 1 else '.pyc' - - with TemporaryFile() as t, \ - zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp: - zipfp.writepy(packagedir) - - names = zipfp.namelist() - self.assertIn('email/__init__' + ext, names) - self.assertIn('email/mime/text' + ext, names) - - def test_write_python_directory(self): - os.mkdir(TESTFN2) - try: - with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: - fp.write("print(42)\n") - - with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp: - fp.write("print(42 * 42)\n") - - with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp: - fp.write("bla bla bla\n") - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - zipfp.writepy(TESTFN2) - - names = zipfp.namelist() - self.assertTrue('mod1.pyc' in names or 'mod1.pyo' in names) - self.assertTrue('mod2.pyc' in names or 'mod2.pyo' in names) - self.assertNotIn('mod2.txt', names) - - finally: - shutil.rmtree(TESTFN2) - - def test_write_non_pyfile(self): - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - with open(TESTFN, 'w') as f: - f.write('most definitely not a python file') - self.assertRaises(RuntimeError, zipfp.writepy, TESTFN) - os.remove(TESTFN) - - def test_write_pyfile_bad_syntax(self): - os.mkdir(TESTFN2) - try: - with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: - fp.write("Bad syntax in python file\n") - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - # syntax errors are printed to stdout - with captured_stdout() as s: - zipfp.writepy(os.path.join(TESTFN2, "mod1.py")) - - self.assertIn("SyntaxError", s.getvalue()) - - # as it will not have compiled the python file, it will - # include the .py file not .pyc or .pyo - names = zipfp.namelist() - self.assertIn('mod1.py', names) - self.assertNotIn('mod1.pyc', names) - self.assertNotIn('mod1.pyo', names) - - finally: - shutil.rmtree(TESTFN2) - -class OtherTests(unittest.TestCase): - zips_with_bad_crc = { - zipfile.ZIP_STORED: ( - b'PK\003\004\024\0\0\0\0\0 \213\212;:r' - b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af' - b'ilehello,AworldP' - b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:' - b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0' - b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi' - b'lePK\005\006\0\0\0\0\001\0\001\0003\000' - b'\0\0/\0\0\0\0\0'), - zipfile.ZIP_DEFLATED: ( - b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA' - b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' - b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0' - b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n' - b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00' - b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00' - b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00'), - zipfile.ZIP_BZIP2: ( - b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA' - b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' - b'ileBZh91AY&SY\xd4\xa8\xca' - b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5' - b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f' - b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14' - b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8' - b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK' - b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00' - b'\x00\x00\x00\x00'), - zipfile.ZIP_LZMA: ( - b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA' - b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' - b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I' - b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK' - b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA' - b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil' - b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00' - b'\x00>\x00\x00\x00\x00\x00'), - } + self.assertIsNone(zipfp2.fp, 'zipfp is not closed') def test_unsupported_version(self): # File has an extract_version of 120 @@ -1027,10 +842,19 @@ b'\x00!p\xa1@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00xPK\x05\x06' b'\x00\x00\x00\x00\x01\x00\x01\x00/\x00\x00\x00\x1f\x00\x00\x00\x00\x00') + self.assertRaises(NotImplementedError, zipfile.ZipFile, io.BytesIO(data), 'r') - def test_unicode_filenames(self): + @requires_zlib + def test_read_unicode_filenames(self): + # bug #10801 + fname = findfile('zip_cp437_header.zip') + with zipfile.ZipFile(fname) as zipfp: + for name in zipfp.namelist(): + zipfp.open(name).close() + + def test_write_unicode_filenames(self): with zipfile.ZipFile(TESTFN, "w") as zf: zf.writestr("foo.txt", "Test for unicode filename") zf.writestr("\xf6.txt", "Test for unicode filename") @@ -1078,20 +902,16 @@ # - passing a filename with open(TESTFN, "w") as fp: fp.write("this is not a legal zip file\n") - chk = zipfile.is_zipfile(TESTFN) - self.assertFalse(chk) + self.assertFalse(zipfile.is_zipfile(TESTFN)) # - passing a file object with open(TESTFN, "rb") as fp: - chk = zipfile.is_zipfile(fp) - self.assertTrue(not chk) + self.assertFalse(zipfile.is_zipfile(fp)) # - passing a file-like object fp = io.BytesIO() fp.write(b"this is not a legal zip file\n") - chk = zipfile.is_zipfile(fp) - self.assertTrue(not chk) + self.assertFalse(zipfile.is_zipfile(fp)) fp.seek(0, 0) - chk = zipfile.is_zipfile(fp) - self.assertTrue(not chk) + self.assertFalse(zipfile.is_zipfile(fp)) def test_damaged_zipfile(self): """Check that zipfiles with missing bytes at the end raise BadZipFile.""" @@ -1113,22 +933,18 @@ with zipfile.ZipFile(TESTFN, mode="w") as zipf: zipf.writestr("foo.txt", b"O, for a Muse of Fire!") - chk = zipfile.is_zipfile(TESTFN) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(TESTFN)) # - passing a file object with open(TESTFN, "rb") as fp: - chk = zipfile.is_zipfile(fp) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(fp)) fp.seek(0, 0) zip_contents = fp.read() # - passing a file-like object fp = io.BytesIO() fp.write(zip_contents) - chk = zipfile.is_zipfile(fp) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(fp)) fp.seek(0, 0) - chk = zipfile.is_zipfile(fp) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(fp)) def test_non_existent_file_raises_IOError(self): # make sure we don't raise an AttributeError when a partially-constructed @@ -1309,93 +1125,6 @@ with zipfile.ZipFile(TESTFN, "r") as zipf: self.assertEqual(zipf.comment, b"this is a comment") - def check_testzip_with_bad_crc(self, compression): - """Tests that files with bad CRCs return their name from testzip.""" - zipdata = self.zips_with_bad_crc[compression] - - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - # testzip returns the name of the first corrupt file, or None - self.assertEqual('afile', zipf.testzip()) - - def test_testzip_with_bad_crc_stored(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_STORED) - - @requires_zlib - def test_testzip_with_bad_crc_deflated(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_testzip_with_bad_crc_bzip2(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_BZIP2) - - @requires_lzma - def test_testzip_with_bad_crc_lzma(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_LZMA) - - def check_read_with_bad_crc(self, compression): - """Tests that files with bad CRCs raise a BadZipFile exception when read.""" - zipdata = self.zips_with_bad_crc[compression] - - # Using ZipFile.read() - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile') - - # Using ZipExtFile.read() - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - with zipf.open('afile', 'r') as corrupt_file: - self.assertRaises(zipfile.BadZipFile, corrupt_file.read) - - # Same with small reads (in order to exercise the buffering logic) - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - with zipf.open('afile', 'r') as corrupt_file: - corrupt_file.MIN_READ_SIZE = 2 - with self.assertRaises(zipfile.BadZipFile): - while corrupt_file.read(2): - pass - - def test_read_with_bad_crc_stored(self): - self.check_read_with_bad_crc(zipfile.ZIP_STORED) - - @requires_zlib - def test_read_with_bad_crc_deflated(self): - self.check_read_with_bad_crc(zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_read_with_bad_crc_bzip2(self): - self.check_read_with_bad_crc(zipfile.ZIP_BZIP2) - - @requires_lzma - def test_read_with_bad_crc_lzma(self): - self.check_read_with_bad_crc(zipfile.ZIP_LZMA) - - def check_read_return_size(self, compression): - # Issue #9837: ZipExtFile.read() shouldn't return more bytes - # than requested. - for test_size in (1, 4095, 4096, 4097, 16384): - file_size = test_size + 1 - junk = b''.join(struct.pack('B', randint(0, 255)) - for x in range(file_size)) - with zipfile.ZipFile(io.BytesIO(), "w", compression) as zipf: - zipf.writestr('foo', junk) - with zipf.open('foo', 'r') as fp: - buf = fp.read(test_size) - self.assertEqual(len(buf), test_size) - - def test_read_return_size_stored(self): - self.check_read_return_size(zipfile.ZIP_STORED) - - @requires_zlib - def test_read_return_size_deflated(self): - self.check_read_return_size(zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_read_return_size_bzip2(self): - self.check_read_return_size(zipfile.ZIP_BZIP2) - - @requires_lzma - def test_read_return_size_lzma(self): - self.check_read_return_size(zipfile.ZIP_LZMA) - def test_empty_zipfile(self): # Check that creating a file in 'w' or 'a' mode and closing without # adding any files to the archives creates a valid empty ZIP file @@ -1430,6 +1159,93 @@ unlink(TESTFN2) +class AbstractBadCrcTests: + def test_testzip_with_bad_crc(self): + """Tests that files with bad CRCs return their name from testzip.""" + zipdata = self.zip_with_bad_crc + + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + # testzip returns the name of the first corrupt file, or None + self.assertEqual('afile', zipf.testzip()) + + def test_read_with_bad_crc(self): + """Tests that files with bad CRCs raise a BadZipFile exception when read.""" + zipdata = self.zip_with_bad_crc + + # Using ZipFile.read() + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile') + + # Using ZipExtFile.read() + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + with zipf.open('afile', 'r') as corrupt_file: + self.assertRaises(zipfile.BadZipFile, corrupt_file.read) + + # Same with small reads (in order to exercise the buffering logic) + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + with zipf.open('afile', 'r') as corrupt_file: + corrupt_file.MIN_READ_SIZE = 2 + with self.assertRaises(zipfile.BadZipFile): + while corrupt_file.read(2): + pass + + +class StoredBadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_STORED + zip_with_bad_crc = ( + b'PK\003\004\024\0\0\0\0\0 \213\212;:r' + b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af' + b'ilehello,AworldP' + b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:' + b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0' + b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi' + b'lePK\005\006\0\0\0\0\001\0\001\0003\000' + b'\0\0/\0\0\0\0\0') + + at requires_zlib +class DeflateBadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_DEFLATED + zip_with_bad_crc = ( + b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA' + b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' + b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0' + b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n' + b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05' + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00' + b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00' + b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00') + + at requires_bz2 +class Bzip2BadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_BZIP2 + zip_with_bad_crc = ( + b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA' + b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' + b'ileBZh91AY&SY\xd4\xa8\xca' + b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5' + b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f' + b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14' + b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8' + b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK' + b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00' + b'\x00\x00\x00\x00') + + at requires_lzma +class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_LZMA + zip_with_bad_crc = ( + b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA' + b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' + b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I' + b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK' + b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA' + b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil' + b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00' + b'\x00>\x00\x00\x00\x00\x00') + + class DecryptionTests(unittest.TestCase): """Check that ZIP decryption works. Since the library does not support encryption at the moment, we use a pre-generated encrypted @@ -1495,13 +1311,14 @@ self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python") self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python") +class AbstractTestsWithRandomBinaryFiles: + @classmethod + def setUpClass(cls): + datacount = randint(16, 64)*1024 + randint(1, 1024) + cls.data = b''.join(struct.pack(' http://hg.python.org/cpython/rev/5812a3683402 changeset: 84790:5812a3683402 parent: 84788:84d6c1c0665e parent: 84789:bb63f813a00f user: Serhiy Storchaka date: Mon Jul 22 21:02:14 2013 +0300 summary: Issue #17944: test_zipfile now discoverable and uses subclassing to generate tests for different compression types. Fixed a bug with skipping some tests due to use of exhausted iterators. files: Lib/test/test_zipfile.py | 1438 ++++++++++--------------- Misc/NEWS | 4 + 2 files changed, 582 insertions(+), 860 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 @@ -10,10 +10,9 @@ from tempfile import TemporaryFile -from random import randint, random -from unittest import skipUnless +from random import randint, random, getrandbits -from test.support import (TESTFN, run_unittest, findfile, unlink, +from test.support import (TESTFN, findfile, unlink, requires_zlib, requires_bz2, requires_lzma, captured_stdout) @@ -27,14 +26,24 @@ ('ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'), ('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3', '6y7u8i9o0p')] +def get_files(test): + yield TESTFN2 + with TemporaryFile() as f: + yield f + test.assertFalse(f.closed) + with io.BytesIO() as f: + yield f + test.assertFalse(f.closed) -class TestsWithSourceFile(unittest.TestCase): +class AbstractTestsWithSourceFile: + @classmethod + def setUpClass(cls): + cls.line_gen = [bytes("Zipfile test line %d. random float: %f\n" % + (i, random()), "ascii") + for i in range(FIXEDTEST_SIZE)] + cls.data = b''.join(cls.line_gen) + def setUp(self): - self.line_gen = (bytes("Zipfile test line %d. random float: %f" % - (i, random()), "ascii") - for i in range(FIXEDTEST_SIZE)) - self.data = b'\n'.join(self.line_gen) + b'\n' - # Make a source file with some lines with open(TESTFN, "wb") as fp: fp.write(self.data) @@ -97,12 +106,10 @@ # Check that testzip doesn't raise an exception zipfp.testzip() - if not isinstance(f, str): - f.close() - def test_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_STORED) + def test_basic(self): + for f in get_files(self): + self.zip_test(f, self.compression) def zip_open_test(self, f, compression): self.make_test_archive(f, compression) @@ -127,30 +134,10 @@ self.assertEqual(b''.join(zipdata1), self.data) self.assertEqual(b''.join(zipdata2), self.data) - if not isinstance(f, str): - f.close() - def test_open_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_STORED) - - def test_open_via_zip_info(self): - # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: - zipfp.writestr("name", "foo") - zipfp.writestr("name", "bar") - - with zipfile.ZipFile(TESTFN2, "r") as zipfp: - infos = zipfp.infolist() - data = b"" - for info in infos: - with zipfp.open(info) as zipopen: - data += zipopen.read() - self.assertTrue(data == b"foobar" or data == b"barfoo") - data = b"" - for info in infos: - data += zipfp.read(info) - self.assertTrue(data == b"foobar" or data == b"barfoo") + def test_open(self): + for f in get_files(self): + self.zip_open_test(f, self.compression) def zip_random_open_test(self, f, compression): self.make_test_archive(f, compression) @@ -166,36 +153,17 @@ zipdata1.append(read_data) self.assertEqual(b''.join(zipdata1), self.data) - if not isinstance(f, str): - f.close() - def test_random_open_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_STORED) - - def test_univeral_readaheads(self): - f = io.BytesIO() - - data = b'a\r\n' * 16 * 1024 - zipfp = zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) - zipfp.writestr(TESTFN, data) - zipfp.close() - - data2 = b'' - zipfp = zipfile.ZipFile(f, 'r') - with zipfp.open(TESTFN, 'rU') as zipopen: - for line in zipopen: - data2 += line - zipfp.close() - - self.assertEqual(data, data2.replace(b'\n', b'\r\n')) + def test_random_open(self): + for f in get_files(self): + self.zip_random_open_test(f, self.compression) def zip_readline_read_test(self, f, compression): self.make_test_archive(f, compression) # Read the ZIP archive - zipfp = zipfile.ZipFile(f, "r") - with zipfp.open(TESTFN) as zipopen: + with zipfile.ZipFile(f, "r") as zipfp, \ + zipfp.open(TESTFN) as zipopen: data = b'' while True: read = zipopen.readline() @@ -209,9 +177,11 @@ data += read self.assertEqual(data, self.data) - zipfp.close() - if not isinstance(f, str): - f.close() + + def test_readline_read(self): + # Issue #7610: calls to readline() interleaved with calls to read(). + for f in get_files(self): + self.zip_readline_read_test(f, self.compression) def zip_readline_test(self, f, compression): self.make_test_archive(f, compression) @@ -221,9 +191,11 @@ with zipfp.open(TESTFN) as zipopen: for line in self.line_gen: linedata = zipopen.readline() - self.assertEqual(linedata, line + '\n') - if not isinstance(f, str): - f.close() + self.assertEqual(linedata, line) + + def test_readline(self): + for f in get_files(self): + self.zip_readline_test(f, self.compression) def zip_readlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -233,9 +205,11 @@ with zipfp.open(TESTFN) as zipopen: ziplines = zipopen.readlines() for line, zipline in zip(self.line_gen, ziplines): - self.assertEqual(zipline, line + '\n') - if not isinstance(f, str): - f.close() + self.assertEqual(zipline, line) + + def test_readlines(self): + for f in get_files(self): + self.zip_readlines_test(f, self.compression) def zip_iterlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -244,173 +218,64 @@ with zipfile.ZipFile(f, "r") as zipfp: with zipfp.open(TESTFN) as zipopen: for line, zipline in zip(self.line_gen, zipopen): - self.assertEqual(zipline, line + '\n') - if not isinstance(f, str): - f.close() + self.assertEqual(zipline, line) - def test_readline_read_stored(self): - # Issue #7610: calls to readline() interleaved with calls to read(). - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_STORED) + def test_iterlines(self): + for f in get_files(self): + self.zip_iterlines_test(f, self.compression) - def test_readline_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_STORED) - - def test_readlines_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_STORED) - - def test_iterlines_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_STORED) - - @requires_zlib - def test_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_DEFLATED) - - - @requires_zlib - def test_open_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_random_open_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_readline_read_deflated(self): - # Issue #7610: calls to readline() interleaved with calls to read(). - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_readline_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_readlines_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_iterlines_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib def test_low_compression(self): """Check for cases where compressed data is larger than original.""" # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp: + with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipfp: zipfp.writestr("strfile", '12') # Get an open object for strfile - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp: + with zipfile.ZipFile(TESTFN2, "r", self.compression) as zipfp: with zipfp.open("strfile") as openobj: self.assertEqual(openobj.read(1), b'1') self.assertEqual(openobj.read(1), b'2') - @requires_bz2 - def test_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_BZIP2) + def test_writestr_compression(self): + zipfp = zipfile.ZipFile(TESTFN2, "w") + zipfp.writestr("b.txt", "hello world", compress_type=self.compression) + info = zipfp.getinfo('b.txt') + self.assertEqual(info.compress_type, self.compression) - @requires_bz2 - def test_open_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_BZIP2) + def test_read_return_size(self): + # Issue #9837: ZipExtFile.read() shouldn't return more bytes + # than requested. + for test_size in (1, 4095, 4096, 4097, 16384): + file_size = test_size + 1 + junk = getrandbits(8 * file_size).to_bytes(file_size, 'little') + with zipfile.ZipFile(io.BytesIO(), "w", self.compression) as zipf: + zipf.writestr('foo', junk) + with zipf.open('foo', 'r') as fp: + buf = fp.read(test_size) + self.assertEqual(len(buf), test_size) - @requires_bz2 - def test_random_open_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_BZIP2) + def tearDown(self): + unlink(TESTFN) + unlink(TESTFN2) - @requires_bz2 - def test_readline_read_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_BZIP2) - @requires_bz2 - def test_readline_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_BZIP2) +class StoredTestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_STORED + test_low_compression = None - @requires_bz2 - def test_readlines_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_BZIP2) + def zip_test_writestr_permissions(self, f, compression): + # Make sure that writestr creates files with mode 0600, + # when it is passed a name rather than a ZipInfo instance. - @requires_bz2 - def test_iterlines_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_BZIP2) + self.make_test_archive(f, compression) + with zipfile.ZipFile(f, "r") as zipfp: + zinfo = zipfp.getinfo('strfile') + self.assertEqual(zinfo.external_attr, 0o600 << 16) - @requires_bz2 - def test_low_compression_bzip2(self): - """Check for cases where compressed data is larger than original.""" - # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_BZIP2) as zipfp: - zipfp.writestr("strfile", '12') - - # Get an open object for strfile - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_BZIP2) as zipfp: - with zipfp.open("strfile") as openobj: - self.assertEqual(openobj.read(1), b'1') - self.assertEqual(openobj.read(1), b'2') - - @requires_lzma - def test_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_open_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_random_open_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_readline_read_lzma(self): - # Issue #7610: calls to readline() interleaved with calls to read(). - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_readline_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_readlines_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_iterlines_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_low_compression_lzma(self): - """Check for cases where compressed data is larger than original.""" - # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_LZMA) as zipfp: - zipfp.writestr("strfile", '12') - - # Get an open object for strfile - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_LZMA) as zipfp: - with zipfp.open("strfile") as openobj: - self.assertEqual(openobj.read(1), b'1') - self.assertEqual(openobj.read(1), b'2') + def test_writestr_permissions(self): + for f in get_files(self): + self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED) def test_absolute_arcnames(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: @@ -470,7 +335,26 @@ with open(TESTFN, "rb") as f: self.assertEqual(zipfp.read(TESTFN), f.read()) - @requires_zlib + def test_write_to_readonly(self): + """Check that trying to call write() on a readonly ZipFile object + raises a RuntimeError.""" + with zipfile.ZipFile(TESTFN2, mode="w") as zipfp: + zipfp.writestr("somefile.txt", "bogus") + + with zipfile.ZipFile(TESTFN2, mode="r") as zipfp: + self.assertRaises(RuntimeError, zipfp.write, TESTFN) + + def test_add_file_before_1980(self): + # Set atime and mtime to 1970-01-01 + os.utime(TESTFN, (0, 0)) + with zipfile.ZipFile(TESTFN2, "w") as zipfp: + self.assertRaises(ValueError, zipfp.write, TESTFN) + + at requires_zlib +class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_DEFLATED + def test_per_file_compression(self): """Check that files within a Zip archive can have different compression options.""" @@ -482,15 +366,263 @@ self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED) self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED) - def test_write_to_readonly(self): - """Check that trying to call write() on a readonly ZipFile object - raises a RuntimeError.""" - with zipfile.ZipFile(TESTFN2, mode="w") as zipfp: - zipfp.writestr("somefile.txt", "bogus") + at requires_bz2 +class Bzip2TestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_BZIP2 - with zipfile.ZipFile(TESTFN2, mode="r") as zipfp: - self.assertRaises(RuntimeError, zipfp.write, TESTFN) + at requires_lzma +class LzmaTestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_LZMA + +class AbstractTestZip64InSmallFiles: + # These tests test the ZIP64 functionality without using large files, + # see test_zipfile64 for proper tests. + + @classmethod + def setUpClass(cls): + line_gen = (bytes("Test of zipfile line %d." % i, "ascii") + for i in range(0, FIXEDTEST_SIZE)) + cls.data = b'\n'.join(line_gen) + + def setUp(self): + self._limit = zipfile.ZIP64_LIMIT + zipfile.ZIP64_LIMIT = 5 + + # Make a source file with some lines + with open(TESTFN, "wb") as fp: + fp.write(self.data) + + def zip_test(self, f, compression): + # Create the ZIP archive + with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp: + zipfp.write(TESTFN, "another.name") + zipfp.write(TESTFN, TESTFN) + zipfp.writestr("strfile", self.data) + + # Read the ZIP archive + with zipfile.ZipFile(f, "r", compression) as zipfp: + self.assertEqual(zipfp.read(TESTFN), self.data) + self.assertEqual(zipfp.read("another.name"), self.data) + self.assertEqual(zipfp.read("strfile"), self.data) + + # Print the ZIP directory + fp = io.StringIO() + zipfp.printdir(fp) + + directory = fp.getvalue() + lines = directory.splitlines() + self.assertEqual(len(lines), 4) # Number of files + header + + self.assertIn('File Name', lines[0]) + self.assertIn('Modified', lines[0]) + self.assertIn('Size', lines[0]) + + fn, date, time_, size = lines[1].split() + self.assertEqual(fn, 'another.name') + self.assertTrue(time.strptime(date, '%Y-%m-%d')) + self.assertTrue(time.strptime(time_, '%H:%M:%S')) + self.assertEqual(size, str(len(self.data))) + + # Check the namelist + names = zipfp.namelist() + self.assertEqual(len(names), 3) + self.assertIn(TESTFN, names) + self.assertIn("another.name", names) + self.assertIn("strfile", names) + + # Check infolist + infos = zipfp.infolist() + names = [i.filename for i in infos] + self.assertEqual(len(names), 3) + self.assertIn(TESTFN, names) + self.assertIn("another.name", names) + self.assertIn("strfile", names) + for i in infos: + self.assertEqual(i.file_size, len(self.data)) + + # check getinfo + for nm in (TESTFN, "another.name", "strfile"): + info = zipfp.getinfo(nm) + self.assertEqual(info.filename, nm) + self.assertEqual(info.file_size, len(self.data)) + + # Check that testzip doesn't raise an exception + zipfp.testzip() + + def test_basic(self): + for f in get_files(self): + self.zip_test(f, self.compression) + + def tearDown(self): + zipfile.ZIP64_LIMIT = self._limit + unlink(TESTFN) + unlink(TESTFN2) + + +class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_STORED + + def large_file_exception_test(self, f, compression): + with zipfile.ZipFile(f, "w", compression) as zipfp: + self.assertRaises(zipfile.LargeZipFile, + zipfp.write, TESTFN, "another.name") + + def large_file_exception_test2(self, f, compression): + with zipfile.ZipFile(f, "w", compression) as zipfp: + self.assertRaises(zipfile.LargeZipFile, + zipfp.writestr, "another.name", self.data) + + def test_large_file_exception(self): + for f in get_files(self): + self.large_file_exception_test(f, zipfile.ZIP_STORED) + self.large_file_exception_test2(f, zipfile.ZIP_STORED) + + def test_absolute_arcnames(self): + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, + allowZip64=True) as zipfp: + zipfp.write(TESTFN, "/absolute") + + with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp: + self.assertEqual(zipfp.namelist(), ["absolute"]) + + at requires_zlib +class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_DEFLATED + + at requires_bz2 +class Bzip2TestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_BZIP2 + + at requires_lzma +class LzmaTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_LZMA + + +class PyZipFileTests(unittest.TestCase): + def assertCompiledIn(self, name, namelist): + if name + 'o' not in namelist: + self.assertIn(name + 'c', namelist) + + def test_write_pyfile(self): + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + fn = __file__ + if fn.endswith('.pyc') or fn.endswith('.pyo'): + path_split = fn.split(os.sep) + if os.altsep is not None: + path_split.extend(fn.split(os.altsep)) + if '__pycache__' in path_split: + fn = importlib.util.source_from_cache(fn) + else: + fn = fn[:-1] + + zipfp.writepy(fn) + + bn = os.path.basename(fn) + self.assertNotIn(bn, zipfp.namelist()) + self.assertCompiledIn(bn, zipfp.namelist()) + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + fn = __file__ + if fn.endswith(('.pyc', '.pyo')): + fn = fn[:-1] + + zipfp.writepy(fn, "testpackage") + + bn = "%s/%s" % ("testpackage", os.path.basename(fn)) + self.assertNotIn(bn, zipfp.namelist()) + self.assertCompiledIn(bn, zipfp.namelist()) + + def test_write_python_package(self): + import email + packagedir = os.path.dirname(email.__file__) + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + zipfp.writepy(packagedir) + + # Check for a couple of modules at different levels of the + # hierarchy + names = zipfp.namelist() + self.assertCompiledIn('email/__init__.py', names) + self.assertCompiledIn('email/mime/text.py', names) + + def test_write_with_optimization(self): + import email + packagedir = os.path.dirname(email.__file__) + # use .pyc if running test in optimization mode, + # use .pyo if running test in debug mode + optlevel = 1 if __debug__ else 0 + ext = '.pyo' if optlevel == 1 else '.pyc' + + with TemporaryFile() as t, \ + zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp: + zipfp.writepy(packagedir) + + names = zipfp.namelist() + self.assertIn('email/__init__' + ext, names) + self.assertIn('email/mime/text' + ext, names) + + def test_write_python_directory(self): + os.mkdir(TESTFN2) + try: + with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: + fp.write("print(42)\n") + + with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp: + fp.write("print(42 * 42)\n") + + with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp: + fp.write("bla bla bla\n") + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + zipfp.writepy(TESTFN2) + + names = zipfp.namelist() + self.assertCompiledIn('mod1.py', names) + self.assertCompiledIn('mod2.py', names) + self.assertNotIn('mod2.txt', names) + + finally: + shutil.rmtree(TESTFN2) + + def test_write_non_pyfile(self): + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + with open(TESTFN, 'w') as f: + f.write('most definitely not a python file') + self.assertRaises(RuntimeError, zipfp.writepy, TESTFN) + os.remove(TESTFN) + + def test_write_pyfile_bad_syntax(self): + os.mkdir(TESTFN2) + try: + with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: + fp.write("Bad syntax in python file\n") + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + # syntax errors are printed to stdout + with captured_stdout() as s: + zipfp.writepy(os.path.join(TESTFN2, "mod1.py")) + + self.assertIn("SyntaxError", s.getvalue()) + + # as it will not have compiled the python file, it will + # include the .py file not .pyc or .pyo + names = zipfp.namelist() + self.assertIn('mod1.py', names) + self.assertNotIn('mod1.pyc', names) + self.assertNotIn('mod1.pyo', names) + + finally: + shutil.rmtree(TESTFN2) + + +class ExtractTests(unittest.TestCase): def test_extract(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: for fpath, fdata in SMALL_TEST_DATA: @@ -636,47 +768,40 @@ os.remove(TESTFN2) - def test_writestr_compression_stored(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("a.txt", "hello world", compress_type=zipfile.ZIP_STORED) - info = zipfp.getinfo('a.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_STORED) - @requires_zlib - def test_writestr_compression_deflated(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_DEFLATED) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_DEFLATED) +class OtherTests(unittest.TestCase): + def test_open_via_zip_info(self): + # Create the ZIP archive + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: + zipfp.writestr("name", "foo") + zipfp.writestr("name", "bar") - @requires_bz2 - def test_writestr_compression_bzip2(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_BZIP2) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_BZIP2) + with zipfile.ZipFile(TESTFN2, "r") as zipfp: + infos = zipfp.infolist() + data = b"" + for info in infos: + with zipfp.open(info) as zipopen: + data += zipopen.read() + self.assertIn(data, {b"foobar", b"barfoo"}) + data = b"" + for info in infos: + data += zipfp.read(info) + self.assertIn(data, {b"foobar", b"barfoo"}) - @requires_lzma - def test_writestr_compression_lzma(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_LZMA) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_LZMA) + def test_universal_readaheads(self): + f = io.BytesIO() - def zip_test_writestr_permissions(self, f, compression): - # Make sure that writestr creates files with mode 0600, - # when it is passed a name rather than a ZipInfo instance. + data = b'a\r\n' * 16 * 1024 + with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.writestr(TESTFN, data) - self.make_test_archive(f, compression) - with zipfile.ZipFile(f, "r") as zipfp: - zinfo = zipfp.getinfo('strfile') - self.assertEqual(zinfo.external_attr, 0o600 << 16) - if not isinstance(f, str): - f.close() + data2 = b'' + with zipfile.ZipFile(f, 'r') as zipfp, \ + zipfp.open(TESTFN, 'rU') as zipopen: + for line in zipopen: + data2 += line - def test_writestr_permissions(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED) + self.assertEqual(data, data2.replace(b'\n', b'\r\n')) def test_writestr_extended_local_header_issue1202(self): with zipfile.ZipFile(TESTFN2, 'w') as orig_zip: @@ -690,12 +815,12 @@ with zipfile.ZipFile(TESTFN2, "w") as zipfp: for fpath, fdata in SMALL_TEST_DATA: zipfp.writestr(fpath, fdata) - self.assertTrue(zipfp.fp is not None, 'zipfp is not open') - self.assertTrue(zipfp.fp is None, 'zipfp is not closed') + self.assertIsNotNone(zipfp.fp, 'zipfp is not open') + self.assertIsNone(zipfp.fp, 'zipfp is not closed') with zipfile.ZipFile(TESTFN2, "r") as zipfp: - self.assertTrue(zipfp.fp is not None, 'zipfp is not open') - self.assertTrue(zipfp.fp is None, 'zipfp is not closed') + self.assertIsNotNone(zipfp.fp, 'zipfp is not open') + self.assertIsNone(zipfp.fp, 'zipfp is not closed') def test_close_on_exception(self): """Check that the zipfile is closed if an exception is raised in the @@ -708,317 +833,7 @@ with zipfile.ZipFile(TESTFN2, "r") as zipfp2: raise zipfile.BadZipFile() except zipfile.BadZipFile: - self.assertTrue(zipfp2.fp is None, 'zipfp is not closed') - - def test_add_file_before_1980(self): - # Set atime and mtime to 1970-01-01 - os.utime(TESTFN, (0, 0)) - with zipfile.ZipFile(TESTFN2, "w") as zipfp: - self.assertRaises(ValueError, zipfp.write, TESTFN) - - - - - - - - @requires_zlib - def test_unicode_filenames(self): - # bug #10801 - fname = findfile('zip_cp437_header.zip') - with zipfile.ZipFile(fname) as zipfp: - for name in zipfp.namelist(): - zipfp.open(name).close() - - def tearDown(self): - unlink(TESTFN) - unlink(TESTFN2) - - -class TestZip64InSmallFiles(unittest.TestCase): - # These tests test the ZIP64 functionality without using large files, - # see test_zipfile64 for proper tests. - - def setUp(self): - self._limit = zipfile.ZIP64_LIMIT - zipfile.ZIP64_LIMIT = 5 - - line_gen = (bytes("Test of zipfile line %d." % i, "ascii") - for i in range(0, FIXEDTEST_SIZE)) - self.data = b'\n'.join(line_gen) - - # Make a source file with some lines - with open(TESTFN, "wb") as fp: - fp.write(self.data) - - def large_file_exception_test(self, f, compression): - with zipfile.ZipFile(f, "w", compression) as zipfp: - self.assertRaises(zipfile.LargeZipFile, - zipfp.write, TESTFN, "another.name") - - def large_file_exception_test2(self, f, compression): - with zipfile.ZipFile(f, "w", compression) as zipfp: - self.assertRaises(zipfile.LargeZipFile, - zipfp.writestr, "another.name", self.data) - if not isinstance(f, str): - f.close() - - def test_large_file_exception(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.large_file_exception_test(f, zipfile.ZIP_STORED) - self.large_file_exception_test2(f, zipfile.ZIP_STORED) - - def zip_test(self, f, compression): - # Create the ZIP archive - with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp: - zipfp.write(TESTFN, "another.name") - zipfp.write(TESTFN, TESTFN) - zipfp.writestr("strfile", self.data) - - # Read the ZIP archive - with zipfile.ZipFile(f, "r", compression) as zipfp: - self.assertEqual(zipfp.read(TESTFN), self.data) - self.assertEqual(zipfp.read("another.name"), self.data) - self.assertEqual(zipfp.read("strfile"), self.data) - - # Print the ZIP directory - fp = io.StringIO() - zipfp.printdir(fp) - - directory = fp.getvalue() - lines = directory.splitlines() - self.assertEqual(len(lines), 4) # Number of files + header - - self.assertIn('File Name', lines[0]) - self.assertIn('Modified', lines[0]) - self.assertIn('Size', lines[0]) - - fn, date, time_, size = lines[1].split() - self.assertEqual(fn, 'another.name') - self.assertTrue(time.strptime(date, '%Y-%m-%d')) - self.assertTrue(time.strptime(time_, '%H:%M:%S')) - self.assertEqual(size, str(len(self.data))) - - # Check the namelist - names = zipfp.namelist() - self.assertEqual(len(names), 3) - self.assertIn(TESTFN, names) - self.assertIn("another.name", names) - self.assertIn("strfile", names) - - # Check infolist - infos = zipfp.infolist() - names = [i.filename for i in infos] - self.assertEqual(len(names), 3) - self.assertIn(TESTFN, names) - self.assertIn("another.name", names) - self.assertIn("strfile", names) - for i in infos: - self.assertEqual(i.file_size, len(self.data)) - - # check getinfo - for nm in (TESTFN, "another.name", "strfile"): - info = zipfp.getinfo(nm) - self.assertEqual(info.filename, nm) - self.assertEqual(info.file_size, len(self.data)) - - # Check that testzip doesn't raise an exception - zipfp.testzip() - if not isinstance(f, str): - f.close() - - def test_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_STORED) - - @requires_zlib - def test_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_BZIP2) - - @requires_lzma - def test_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_LZMA) - - def test_absolute_arcnames(self): - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, - allowZip64=True) as zipfp: - zipfp.write(TESTFN, "/absolute") - - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp: - self.assertEqual(zipfp.namelist(), ["absolute"]) - - def tearDown(self): - zipfile.ZIP64_LIMIT = self._limit - unlink(TESTFN) - unlink(TESTFN2) - - -class PyZipFileTests(unittest.TestCase): - def test_write_pyfile(self): - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - fn = __file__ - if fn.endswith('.pyc') or fn.endswith('.pyo'): - path_split = fn.split(os.sep) - if os.altsep is not None: - path_split.extend(fn.split(os.altsep)) - if '__pycache__' in path_split: - fn = importlib.util.source_from_cache(fn) - else: - fn = fn[:-1] - - zipfp.writepy(fn) - - bn = os.path.basename(fn) - self.assertNotIn(bn, zipfp.namelist()) - self.assertTrue(bn + 'o' in zipfp.namelist() or - bn + 'c' in zipfp.namelist()) - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - fn = __file__ - if fn.endswith(('.pyc', '.pyo')): - fn = fn[:-1] - - zipfp.writepy(fn, "testpackage") - - bn = "%s/%s" % ("testpackage", os.path.basename(fn)) - self.assertNotIn(bn, zipfp.namelist()) - self.assertTrue(bn + 'o' in zipfp.namelist() or - bn + 'c' in zipfp.namelist()) - - def test_write_python_package(self): - import email - packagedir = os.path.dirname(email.__file__) - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - zipfp.writepy(packagedir) - - # Check for a couple of modules at different levels of the - # hierarchy - names = zipfp.namelist() - self.assertTrue('email/__init__.pyo' in names or - 'email/__init__.pyc' in names) - self.assertTrue('email/mime/text.pyo' in names or - 'email/mime/text.pyc' in names) - - def test_write_with_optimization(self): - import email - packagedir = os.path.dirname(email.__file__) - # use .pyc if running test in optimization mode, - # use .pyo if running test in debug mode - optlevel = 1 if __debug__ else 0 - ext = '.pyo' if optlevel == 1 else '.pyc' - - with TemporaryFile() as t, \ - zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp: - zipfp.writepy(packagedir) - - names = zipfp.namelist() - self.assertIn('email/__init__' + ext, names) - self.assertIn('email/mime/text' + ext, names) - - def test_write_python_directory(self): - os.mkdir(TESTFN2) - try: - with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: - fp.write("print(42)\n") - - with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp: - fp.write("print(42 * 42)\n") - - with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp: - fp.write("bla bla bla\n") - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - zipfp.writepy(TESTFN2) - - names = zipfp.namelist() - self.assertTrue('mod1.pyc' in names or 'mod1.pyo' in names) - self.assertTrue('mod2.pyc' in names or 'mod2.pyo' in names) - self.assertNotIn('mod2.txt', names) - - finally: - shutil.rmtree(TESTFN2) - - def test_write_non_pyfile(self): - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - with open(TESTFN, 'w') as f: - f.write('most definitely not a python file') - self.assertRaises(RuntimeError, zipfp.writepy, TESTFN) - os.remove(TESTFN) - - def test_write_pyfile_bad_syntax(self): - os.mkdir(TESTFN2) - try: - with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: - fp.write("Bad syntax in python file\n") - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - # syntax errors are printed to stdout - with captured_stdout() as s: - zipfp.writepy(os.path.join(TESTFN2, "mod1.py")) - - self.assertIn("SyntaxError", s.getvalue()) - - # as it will not have compiled the python file, it will - # include the .py file not .pyc or .pyo - names = zipfp.namelist() - self.assertIn('mod1.py', names) - self.assertNotIn('mod1.pyc', names) - self.assertNotIn('mod1.pyo', names) - - finally: - shutil.rmtree(TESTFN2) - -class OtherTests(unittest.TestCase): - zips_with_bad_crc = { - zipfile.ZIP_STORED: ( - b'PK\003\004\024\0\0\0\0\0 \213\212;:r' - b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af' - b'ilehello,AworldP' - b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:' - b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0' - b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi' - b'lePK\005\006\0\0\0\0\001\0\001\0003\000' - b'\0\0/\0\0\0\0\0'), - zipfile.ZIP_DEFLATED: ( - b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA' - b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' - b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0' - b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n' - b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00' - b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00' - b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00'), - zipfile.ZIP_BZIP2: ( - b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA' - b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' - b'ileBZh91AY&SY\xd4\xa8\xca' - b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5' - b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f' - b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14' - b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8' - b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK' - b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00' - b'\x00\x00\x00\x00'), - zipfile.ZIP_LZMA: ( - b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA' - b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' - b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I' - b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK' - b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA' - b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil' - b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00' - b'\x00>\x00\x00\x00\x00\x00'), - } + self.assertIsNone(zipfp2.fp, 'zipfp is not closed') def test_unsupported_version(self): # File has an extract_version of 120 @@ -1027,10 +842,19 @@ b'\x00!p\xa1@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00xPK\x05\x06' b'\x00\x00\x00\x00\x01\x00\x01\x00/\x00\x00\x00\x1f\x00\x00\x00\x00\x00') + self.assertRaises(NotImplementedError, zipfile.ZipFile, io.BytesIO(data), 'r') - def test_unicode_filenames(self): + @requires_zlib + def test_read_unicode_filenames(self): + # bug #10801 + fname = findfile('zip_cp437_header.zip') + with zipfile.ZipFile(fname) as zipfp: + for name in zipfp.namelist(): + zipfp.open(name).close() + + def test_write_unicode_filenames(self): with zipfile.ZipFile(TESTFN, "w") as zf: zf.writestr("foo.txt", "Test for unicode filename") zf.writestr("\xf6.txt", "Test for unicode filename") @@ -1078,20 +902,16 @@ # - passing a filename with open(TESTFN, "w") as fp: fp.write("this is not a legal zip file\n") - chk = zipfile.is_zipfile(TESTFN) - self.assertFalse(chk) + self.assertFalse(zipfile.is_zipfile(TESTFN)) # - passing a file object with open(TESTFN, "rb") as fp: - chk = zipfile.is_zipfile(fp) - self.assertTrue(not chk) + self.assertFalse(zipfile.is_zipfile(fp)) # - passing a file-like object fp = io.BytesIO() fp.write(b"this is not a legal zip file\n") - chk = zipfile.is_zipfile(fp) - self.assertTrue(not chk) + self.assertFalse(zipfile.is_zipfile(fp)) fp.seek(0, 0) - chk = zipfile.is_zipfile(fp) - self.assertTrue(not chk) + self.assertFalse(zipfile.is_zipfile(fp)) def test_damaged_zipfile(self): """Check that zipfiles with missing bytes at the end raise BadZipFile.""" @@ -1113,22 +933,18 @@ with zipfile.ZipFile(TESTFN, mode="w") as zipf: zipf.writestr("foo.txt", b"O, for a Muse of Fire!") - chk = zipfile.is_zipfile(TESTFN) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(TESTFN)) # - passing a file object with open(TESTFN, "rb") as fp: - chk = zipfile.is_zipfile(fp) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(fp)) fp.seek(0, 0) zip_contents = fp.read() # - passing a file-like object fp = io.BytesIO() fp.write(zip_contents) - chk = zipfile.is_zipfile(fp) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(fp)) fp.seek(0, 0) - chk = zipfile.is_zipfile(fp) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(fp)) def test_non_existent_file_raises_OSError(self): # make sure we don't raise an AttributeError when a partially-constructed @@ -1309,93 +1125,6 @@ with zipfile.ZipFile(TESTFN, "r") as zipf: self.assertEqual(zipf.comment, b"this is a comment") - def check_testzip_with_bad_crc(self, compression): - """Tests that files with bad CRCs return their name from testzip.""" - zipdata = self.zips_with_bad_crc[compression] - - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - # testzip returns the name of the first corrupt file, or None - self.assertEqual('afile', zipf.testzip()) - - def test_testzip_with_bad_crc_stored(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_STORED) - - @requires_zlib - def test_testzip_with_bad_crc_deflated(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_testzip_with_bad_crc_bzip2(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_BZIP2) - - @requires_lzma - def test_testzip_with_bad_crc_lzma(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_LZMA) - - def check_read_with_bad_crc(self, compression): - """Tests that files with bad CRCs raise a BadZipFile exception when read.""" - zipdata = self.zips_with_bad_crc[compression] - - # Using ZipFile.read() - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile') - - # Using ZipExtFile.read() - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - with zipf.open('afile', 'r') as corrupt_file: - self.assertRaises(zipfile.BadZipFile, corrupt_file.read) - - # Same with small reads (in order to exercise the buffering logic) - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - with zipf.open('afile', 'r') as corrupt_file: - corrupt_file.MIN_READ_SIZE = 2 - with self.assertRaises(zipfile.BadZipFile): - while corrupt_file.read(2): - pass - - def test_read_with_bad_crc_stored(self): - self.check_read_with_bad_crc(zipfile.ZIP_STORED) - - @requires_zlib - def test_read_with_bad_crc_deflated(self): - self.check_read_with_bad_crc(zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_read_with_bad_crc_bzip2(self): - self.check_read_with_bad_crc(zipfile.ZIP_BZIP2) - - @requires_lzma - def test_read_with_bad_crc_lzma(self): - self.check_read_with_bad_crc(zipfile.ZIP_LZMA) - - def check_read_return_size(self, compression): - # Issue #9837: ZipExtFile.read() shouldn't return more bytes - # than requested. - for test_size in (1, 4095, 4096, 4097, 16384): - file_size = test_size + 1 - junk = b''.join(struct.pack('B', randint(0, 255)) - for x in range(file_size)) - with zipfile.ZipFile(io.BytesIO(), "w", compression) as zipf: - zipf.writestr('foo', junk) - with zipf.open('foo', 'r') as fp: - buf = fp.read(test_size) - self.assertEqual(len(buf), test_size) - - def test_read_return_size_stored(self): - self.check_read_return_size(zipfile.ZIP_STORED) - - @requires_zlib - def test_read_return_size_deflated(self): - self.check_read_return_size(zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_read_return_size_bzip2(self): - self.check_read_return_size(zipfile.ZIP_BZIP2) - - @requires_lzma - def test_read_return_size_lzma(self): - self.check_read_return_size(zipfile.ZIP_LZMA) - def test_empty_zipfile(self): # Check that creating a file in 'w' or 'a' mode and closing without # adding any files to the archives creates a valid empty ZIP file @@ -1430,6 +1159,93 @@ unlink(TESTFN2) +class AbstractBadCrcTests: + def test_testzip_with_bad_crc(self): + """Tests that files with bad CRCs return their name from testzip.""" + zipdata = self.zip_with_bad_crc + + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + # testzip returns the name of the first corrupt file, or None + self.assertEqual('afile', zipf.testzip()) + + def test_read_with_bad_crc(self): + """Tests that files with bad CRCs raise a BadZipFile exception when read.""" + zipdata = self.zip_with_bad_crc + + # Using ZipFile.read() + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile') + + # Using ZipExtFile.read() + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + with zipf.open('afile', 'r') as corrupt_file: + self.assertRaises(zipfile.BadZipFile, corrupt_file.read) + + # Same with small reads (in order to exercise the buffering logic) + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + with zipf.open('afile', 'r') as corrupt_file: + corrupt_file.MIN_READ_SIZE = 2 + with self.assertRaises(zipfile.BadZipFile): + while corrupt_file.read(2): + pass + + +class StoredBadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_STORED + zip_with_bad_crc = ( + b'PK\003\004\024\0\0\0\0\0 \213\212;:r' + b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af' + b'ilehello,AworldP' + b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:' + b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0' + b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi' + b'lePK\005\006\0\0\0\0\001\0\001\0003\000' + b'\0\0/\0\0\0\0\0') + + at requires_zlib +class DeflateBadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_DEFLATED + zip_with_bad_crc = ( + b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA' + b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' + b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0' + b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n' + b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05' + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00' + b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00' + b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00') + + at requires_bz2 +class Bzip2BadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_BZIP2 + zip_with_bad_crc = ( + b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA' + b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' + b'ileBZh91AY&SY\xd4\xa8\xca' + b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5' + b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f' + b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14' + b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8' + b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK' + b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00' + b'\x00\x00\x00\x00') + + at requires_lzma +class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_LZMA + zip_with_bad_crc = ( + b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA' + b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' + b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I' + b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK' + b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA' + b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil' + b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00' + b'\x00>\x00\x00\x00\x00\x00') + + class DecryptionTests(unittest.TestCase): """Check that ZIP decryption works. Since the library does not support encryption at the moment, we use a pre-generated encrypted @@ -1495,13 +1311,14 @@ self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python") self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python") +class AbstractTestsWithRandomBinaryFiles: + @classmethod + def setUpClass(cls): + datacount = randint(16, 64)*1024 + randint(1, 1024) + cls.data = b''.join(struct.pack(' http://hg.python.org/cpython/rev/240adc564539 changeset: 84791:240adc564539 parent: 84788:84d6c1c0665e user: Brian Curtin date: Mon Jul 22 13:07:52 2013 -0500 summary: Fix #18530. Remove extra stat call from posixpath.ismount files: Lib/posixpath.py | 22 ++++++++++++++-------- Misc/NEWS | 3 +++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -182,18 +182,24 @@ def ismount(path): """Test whether a path is a mount point""" - if islink(path): - # A symlink can never be a mount point - return False try: s1 = os.lstat(path) - if isinstance(path, bytes): - parent = join(path, b'..') - else: - parent = join(path, '..') + except OSError: + # It doesn't exist -- so not a mount point. :-) + return False + else: + if stat.S_ISLNK(s1.st_mode): + return False + + if isinstance(path, bytes): + parent = join(path, b'..') + else: + parent = join(path, '..') + try: s2 = os.lstat(parent) except OSError: - return False # It doesn't exist -- so not a mount point :-) + return False + dev1 = s1.st_dev dev2 = s2.st_dev if dev1 != dev2: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -162,6 +162,9 @@ Library ------- +- Issue #18530: Remove additional stat call from posixpath.ismount. + Patch by Alex Gaynor. + - Issue #18514: Fix unreachable Py_DECREF() call in PyCData_FromBaseObj() - Issue #9177: Calling read() or write() now raises ValueError, not -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 20:08:39 2013 From: python-checkins at python.org (brian.curtin) Date: Mon, 22 Jul 2013 20:08:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge?= Message-ID: <3bzW5z37c6z7Lkn@mail.python.org> http://hg.python.org/cpython/rev/ffe9d73b5f8d changeset: 84792:ffe9d73b5f8d parent: 84791:240adc564539 parent: 84790:5812a3683402 user: Brian Curtin date: Mon Jul 22 13:08:21 2013 -0500 summary: Merge files: Lib/test/test_zipfile.py | 1438 ++++++++++--------------- Misc/NEWS | 4 + 2 files changed, 582 insertions(+), 860 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 @@ -10,10 +10,9 @@ from tempfile import TemporaryFile -from random import randint, random -from unittest import skipUnless +from random import randint, random, getrandbits -from test.support import (TESTFN, run_unittest, findfile, unlink, +from test.support import (TESTFN, findfile, unlink, requires_zlib, requires_bz2, requires_lzma, captured_stdout) @@ -27,14 +26,24 @@ ('ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'), ('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3', '6y7u8i9o0p')] +def get_files(test): + yield TESTFN2 + with TemporaryFile() as f: + yield f + test.assertFalse(f.closed) + with io.BytesIO() as f: + yield f + test.assertFalse(f.closed) -class TestsWithSourceFile(unittest.TestCase): +class AbstractTestsWithSourceFile: + @classmethod + def setUpClass(cls): + cls.line_gen = [bytes("Zipfile test line %d. random float: %f\n" % + (i, random()), "ascii") + for i in range(FIXEDTEST_SIZE)] + cls.data = b''.join(cls.line_gen) + def setUp(self): - self.line_gen = (bytes("Zipfile test line %d. random float: %f" % - (i, random()), "ascii") - for i in range(FIXEDTEST_SIZE)) - self.data = b'\n'.join(self.line_gen) + b'\n' - # Make a source file with some lines with open(TESTFN, "wb") as fp: fp.write(self.data) @@ -97,12 +106,10 @@ # Check that testzip doesn't raise an exception zipfp.testzip() - if not isinstance(f, str): - f.close() - def test_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_STORED) + def test_basic(self): + for f in get_files(self): + self.zip_test(f, self.compression) def zip_open_test(self, f, compression): self.make_test_archive(f, compression) @@ -127,30 +134,10 @@ self.assertEqual(b''.join(zipdata1), self.data) self.assertEqual(b''.join(zipdata2), self.data) - if not isinstance(f, str): - f.close() - def test_open_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_STORED) - - def test_open_via_zip_info(self): - # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: - zipfp.writestr("name", "foo") - zipfp.writestr("name", "bar") - - with zipfile.ZipFile(TESTFN2, "r") as zipfp: - infos = zipfp.infolist() - data = b"" - for info in infos: - with zipfp.open(info) as zipopen: - data += zipopen.read() - self.assertTrue(data == b"foobar" or data == b"barfoo") - data = b"" - for info in infos: - data += zipfp.read(info) - self.assertTrue(data == b"foobar" or data == b"barfoo") + def test_open(self): + for f in get_files(self): + self.zip_open_test(f, self.compression) def zip_random_open_test(self, f, compression): self.make_test_archive(f, compression) @@ -166,36 +153,17 @@ zipdata1.append(read_data) self.assertEqual(b''.join(zipdata1), self.data) - if not isinstance(f, str): - f.close() - def test_random_open_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_STORED) - - def test_univeral_readaheads(self): - f = io.BytesIO() - - data = b'a\r\n' * 16 * 1024 - zipfp = zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) - zipfp.writestr(TESTFN, data) - zipfp.close() - - data2 = b'' - zipfp = zipfile.ZipFile(f, 'r') - with zipfp.open(TESTFN, 'rU') as zipopen: - for line in zipopen: - data2 += line - zipfp.close() - - self.assertEqual(data, data2.replace(b'\n', b'\r\n')) + def test_random_open(self): + for f in get_files(self): + self.zip_random_open_test(f, self.compression) def zip_readline_read_test(self, f, compression): self.make_test_archive(f, compression) # Read the ZIP archive - zipfp = zipfile.ZipFile(f, "r") - with zipfp.open(TESTFN) as zipopen: + with zipfile.ZipFile(f, "r") as zipfp, \ + zipfp.open(TESTFN) as zipopen: data = b'' while True: read = zipopen.readline() @@ -209,9 +177,11 @@ data += read self.assertEqual(data, self.data) - zipfp.close() - if not isinstance(f, str): - f.close() + + def test_readline_read(self): + # Issue #7610: calls to readline() interleaved with calls to read(). + for f in get_files(self): + self.zip_readline_read_test(f, self.compression) def zip_readline_test(self, f, compression): self.make_test_archive(f, compression) @@ -221,9 +191,11 @@ with zipfp.open(TESTFN) as zipopen: for line in self.line_gen: linedata = zipopen.readline() - self.assertEqual(linedata, line + '\n') - if not isinstance(f, str): - f.close() + self.assertEqual(linedata, line) + + def test_readline(self): + for f in get_files(self): + self.zip_readline_test(f, self.compression) def zip_readlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -233,9 +205,11 @@ with zipfp.open(TESTFN) as zipopen: ziplines = zipopen.readlines() for line, zipline in zip(self.line_gen, ziplines): - self.assertEqual(zipline, line + '\n') - if not isinstance(f, str): - f.close() + self.assertEqual(zipline, line) + + def test_readlines(self): + for f in get_files(self): + self.zip_readlines_test(f, self.compression) def zip_iterlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -244,173 +218,64 @@ with zipfile.ZipFile(f, "r") as zipfp: with zipfp.open(TESTFN) as zipopen: for line, zipline in zip(self.line_gen, zipopen): - self.assertEqual(zipline, line + '\n') - if not isinstance(f, str): - f.close() + self.assertEqual(zipline, line) - def test_readline_read_stored(self): - # Issue #7610: calls to readline() interleaved with calls to read(). - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_STORED) + def test_iterlines(self): + for f in get_files(self): + self.zip_iterlines_test(f, self.compression) - def test_readline_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_STORED) - - def test_readlines_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_STORED) - - def test_iterlines_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_STORED) - - @requires_zlib - def test_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_DEFLATED) - - - @requires_zlib - def test_open_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_random_open_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_readline_read_deflated(self): - # Issue #7610: calls to readline() interleaved with calls to read(). - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_readline_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_readlines_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib - def test_iterlines_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_DEFLATED) - - @requires_zlib def test_low_compression(self): """Check for cases where compressed data is larger than original.""" # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp: + with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipfp: zipfp.writestr("strfile", '12') # Get an open object for strfile - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp: + with zipfile.ZipFile(TESTFN2, "r", self.compression) as zipfp: with zipfp.open("strfile") as openobj: self.assertEqual(openobj.read(1), b'1') self.assertEqual(openobj.read(1), b'2') - @requires_bz2 - def test_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_BZIP2) + def test_writestr_compression(self): + zipfp = zipfile.ZipFile(TESTFN2, "w") + zipfp.writestr("b.txt", "hello world", compress_type=self.compression) + info = zipfp.getinfo('b.txt') + self.assertEqual(info.compress_type, self.compression) - @requires_bz2 - def test_open_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_BZIP2) + def test_read_return_size(self): + # Issue #9837: ZipExtFile.read() shouldn't return more bytes + # than requested. + for test_size in (1, 4095, 4096, 4097, 16384): + file_size = test_size + 1 + junk = getrandbits(8 * file_size).to_bytes(file_size, 'little') + with zipfile.ZipFile(io.BytesIO(), "w", self.compression) as zipf: + zipf.writestr('foo', junk) + with zipf.open('foo', 'r') as fp: + buf = fp.read(test_size) + self.assertEqual(len(buf), test_size) - @requires_bz2 - def test_random_open_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_BZIP2) + def tearDown(self): + unlink(TESTFN) + unlink(TESTFN2) - @requires_bz2 - def test_readline_read_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_BZIP2) - @requires_bz2 - def test_readline_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_BZIP2) +class StoredTestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_STORED + test_low_compression = None - @requires_bz2 - def test_readlines_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_BZIP2) + def zip_test_writestr_permissions(self, f, compression): + # Make sure that writestr creates files with mode 0600, + # when it is passed a name rather than a ZipInfo instance. - @requires_bz2 - def test_iterlines_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_BZIP2) + self.make_test_archive(f, compression) + with zipfile.ZipFile(f, "r") as zipfp: + zinfo = zipfp.getinfo('strfile') + self.assertEqual(zinfo.external_attr, 0o600 << 16) - @requires_bz2 - def test_low_compression_bzip2(self): - """Check for cases where compressed data is larger than original.""" - # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_BZIP2) as zipfp: - zipfp.writestr("strfile", '12') - - # Get an open object for strfile - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_BZIP2) as zipfp: - with zipfp.open("strfile") as openobj: - self.assertEqual(openobj.read(1), b'1') - self.assertEqual(openobj.read(1), b'2') - - @requires_lzma - def test_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_open_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_open_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_random_open_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_random_open_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_readline_read_lzma(self): - # Issue #7610: calls to readline() interleaved with calls to read(). - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_read_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_readline_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readline_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_readlines_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_readlines_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_iterlines_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_iterlines_test(f, zipfile.ZIP_LZMA) - - @requires_lzma - def test_low_compression_lzma(self): - """Check for cases where compressed data is larger than original.""" - # Create the ZIP archive - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_LZMA) as zipfp: - zipfp.writestr("strfile", '12') - - # Get an open object for strfile - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_LZMA) as zipfp: - with zipfp.open("strfile") as openobj: - self.assertEqual(openobj.read(1), b'1') - self.assertEqual(openobj.read(1), b'2') + def test_writestr_permissions(self): + for f in get_files(self): + self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED) def test_absolute_arcnames(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: @@ -470,7 +335,26 @@ with open(TESTFN, "rb") as f: self.assertEqual(zipfp.read(TESTFN), f.read()) - @requires_zlib + def test_write_to_readonly(self): + """Check that trying to call write() on a readonly ZipFile object + raises a RuntimeError.""" + with zipfile.ZipFile(TESTFN2, mode="w") as zipfp: + zipfp.writestr("somefile.txt", "bogus") + + with zipfile.ZipFile(TESTFN2, mode="r") as zipfp: + self.assertRaises(RuntimeError, zipfp.write, TESTFN) + + def test_add_file_before_1980(self): + # Set atime and mtime to 1970-01-01 + os.utime(TESTFN, (0, 0)) + with zipfile.ZipFile(TESTFN2, "w") as zipfp: + self.assertRaises(ValueError, zipfp.write, TESTFN) + + at requires_zlib +class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_DEFLATED + def test_per_file_compression(self): """Check that files within a Zip archive can have different compression options.""" @@ -482,15 +366,263 @@ self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED) self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED) - def test_write_to_readonly(self): - """Check that trying to call write() on a readonly ZipFile object - raises a RuntimeError.""" - with zipfile.ZipFile(TESTFN2, mode="w") as zipfp: - zipfp.writestr("somefile.txt", "bogus") + at requires_bz2 +class Bzip2TestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_BZIP2 - with zipfile.ZipFile(TESTFN2, mode="r") as zipfp: - self.assertRaises(RuntimeError, zipfp.write, TESTFN) + at requires_lzma +class LzmaTestsWithSourceFile(AbstractTestsWithSourceFile, + unittest.TestCase): + compression = zipfile.ZIP_LZMA + +class AbstractTestZip64InSmallFiles: + # These tests test the ZIP64 functionality without using large files, + # see test_zipfile64 for proper tests. + + @classmethod + def setUpClass(cls): + line_gen = (bytes("Test of zipfile line %d." % i, "ascii") + for i in range(0, FIXEDTEST_SIZE)) + cls.data = b'\n'.join(line_gen) + + def setUp(self): + self._limit = zipfile.ZIP64_LIMIT + zipfile.ZIP64_LIMIT = 5 + + # Make a source file with some lines + with open(TESTFN, "wb") as fp: + fp.write(self.data) + + def zip_test(self, f, compression): + # Create the ZIP archive + with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp: + zipfp.write(TESTFN, "another.name") + zipfp.write(TESTFN, TESTFN) + zipfp.writestr("strfile", self.data) + + # Read the ZIP archive + with zipfile.ZipFile(f, "r", compression) as zipfp: + self.assertEqual(zipfp.read(TESTFN), self.data) + self.assertEqual(zipfp.read("another.name"), self.data) + self.assertEqual(zipfp.read("strfile"), self.data) + + # Print the ZIP directory + fp = io.StringIO() + zipfp.printdir(fp) + + directory = fp.getvalue() + lines = directory.splitlines() + self.assertEqual(len(lines), 4) # Number of files + header + + self.assertIn('File Name', lines[0]) + self.assertIn('Modified', lines[0]) + self.assertIn('Size', lines[0]) + + fn, date, time_, size = lines[1].split() + self.assertEqual(fn, 'another.name') + self.assertTrue(time.strptime(date, '%Y-%m-%d')) + self.assertTrue(time.strptime(time_, '%H:%M:%S')) + self.assertEqual(size, str(len(self.data))) + + # Check the namelist + names = zipfp.namelist() + self.assertEqual(len(names), 3) + self.assertIn(TESTFN, names) + self.assertIn("another.name", names) + self.assertIn("strfile", names) + + # Check infolist + infos = zipfp.infolist() + names = [i.filename for i in infos] + self.assertEqual(len(names), 3) + self.assertIn(TESTFN, names) + self.assertIn("another.name", names) + self.assertIn("strfile", names) + for i in infos: + self.assertEqual(i.file_size, len(self.data)) + + # check getinfo + for nm in (TESTFN, "another.name", "strfile"): + info = zipfp.getinfo(nm) + self.assertEqual(info.filename, nm) + self.assertEqual(info.file_size, len(self.data)) + + # Check that testzip doesn't raise an exception + zipfp.testzip() + + def test_basic(self): + for f in get_files(self): + self.zip_test(f, self.compression) + + def tearDown(self): + zipfile.ZIP64_LIMIT = self._limit + unlink(TESTFN) + unlink(TESTFN2) + + +class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_STORED + + def large_file_exception_test(self, f, compression): + with zipfile.ZipFile(f, "w", compression) as zipfp: + self.assertRaises(zipfile.LargeZipFile, + zipfp.write, TESTFN, "another.name") + + def large_file_exception_test2(self, f, compression): + with zipfile.ZipFile(f, "w", compression) as zipfp: + self.assertRaises(zipfile.LargeZipFile, + zipfp.writestr, "another.name", self.data) + + def test_large_file_exception(self): + for f in get_files(self): + self.large_file_exception_test(f, zipfile.ZIP_STORED) + self.large_file_exception_test2(f, zipfile.ZIP_STORED) + + def test_absolute_arcnames(self): + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, + allowZip64=True) as zipfp: + zipfp.write(TESTFN, "/absolute") + + with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp: + self.assertEqual(zipfp.namelist(), ["absolute"]) + + at requires_zlib +class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_DEFLATED + + at requires_bz2 +class Bzip2TestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_BZIP2 + + at requires_lzma +class LzmaTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_LZMA + + +class PyZipFileTests(unittest.TestCase): + def assertCompiledIn(self, name, namelist): + if name + 'o' not in namelist: + self.assertIn(name + 'c', namelist) + + def test_write_pyfile(self): + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + fn = __file__ + if fn.endswith('.pyc') or fn.endswith('.pyo'): + path_split = fn.split(os.sep) + if os.altsep is not None: + path_split.extend(fn.split(os.altsep)) + if '__pycache__' in path_split: + fn = importlib.util.source_from_cache(fn) + else: + fn = fn[:-1] + + zipfp.writepy(fn) + + bn = os.path.basename(fn) + self.assertNotIn(bn, zipfp.namelist()) + self.assertCompiledIn(bn, zipfp.namelist()) + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + fn = __file__ + if fn.endswith(('.pyc', '.pyo')): + fn = fn[:-1] + + zipfp.writepy(fn, "testpackage") + + bn = "%s/%s" % ("testpackage", os.path.basename(fn)) + self.assertNotIn(bn, zipfp.namelist()) + self.assertCompiledIn(bn, zipfp.namelist()) + + def test_write_python_package(self): + import email + packagedir = os.path.dirname(email.__file__) + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + zipfp.writepy(packagedir) + + # Check for a couple of modules at different levels of the + # hierarchy + names = zipfp.namelist() + self.assertCompiledIn('email/__init__.py', names) + self.assertCompiledIn('email/mime/text.py', names) + + def test_write_with_optimization(self): + import email + packagedir = os.path.dirname(email.__file__) + # use .pyc if running test in optimization mode, + # use .pyo if running test in debug mode + optlevel = 1 if __debug__ else 0 + ext = '.pyo' if optlevel == 1 else '.pyc' + + with TemporaryFile() as t, \ + zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp: + zipfp.writepy(packagedir) + + names = zipfp.namelist() + self.assertIn('email/__init__' + ext, names) + self.assertIn('email/mime/text' + ext, names) + + def test_write_python_directory(self): + os.mkdir(TESTFN2) + try: + with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: + fp.write("print(42)\n") + + with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp: + fp.write("print(42 * 42)\n") + + with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp: + fp.write("bla bla bla\n") + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + zipfp.writepy(TESTFN2) + + names = zipfp.namelist() + self.assertCompiledIn('mod1.py', names) + self.assertCompiledIn('mod2.py', names) + self.assertNotIn('mod2.txt', names) + + finally: + shutil.rmtree(TESTFN2) + + def test_write_non_pyfile(self): + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + with open(TESTFN, 'w') as f: + f.write('most definitely not a python file') + self.assertRaises(RuntimeError, zipfp.writepy, TESTFN) + os.remove(TESTFN) + + def test_write_pyfile_bad_syntax(self): + os.mkdir(TESTFN2) + try: + with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: + fp.write("Bad syntax in python file\n") + + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + # syntax errors are printed to stdout + with captured_stdout() as s: + zipfp.writepy(os.path.join(TESTFN2, "mod1.py")) + + self.assertIn("SyntaxError", s.getvalue()) + + # as it will not have compiled the python file, it will + # include the .py file not .pyc or .pyo + names = zipfp.namelist() + self.assertIn('mod1.py', names) + self.assertNotIn('mod1.pyc', names) + self.assertNotIn('mod1.pyo', names) + + finally: + shutil.rmtree(TESTFN2) + + +class ExtractTests(unittest.TestCase): def test_extract(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: for fpath, fdata in SMALL_TEST_DATA: @@ -636,47 +768,40 @@ os.remove(TESTFN2) - def test_writestr_compression_stored(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("a.txt", "hello world", compress_type=zipfile.ZIP_STORED) - info = zipfp.getinfo('a.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_STORED) - @requires_zlib - def test_writestr_compression_deflated(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_DEFLATED) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_DEFLATED) +class OtherTests(unittest.TestCase): + def test_open_via_zip_info(self): + # Create the ZIP archive + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: + zipfp.writestr("name", "foo") + zipfp.writestr("name", "bar") - @requires_bz2 - def test_writestr_compression_bzip2(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_BZIP2) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_BZIP2) + with zipfile.ZipFile(TESTFN2, "r") as zipfp: + infos = zipfp.infolist() + data = b"" + for info in infos: + with zipfp.open(info) as zipopen: + data += zipopen.read() + self.assertIn(data, {b"foobar", b"barfoo"}) + data = b"" + for info in infos: + data += zipfp.read(info) + self.assertIn(data, {b"foobar", b"barfoo"}) - @requires_lzma - def test_writestr_compression_lzma(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_LZMA) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, zipfile.ZIP_LZMA) + def test_universal_readaheads(self): + f = io.BytesIO() - def zip_test_writestr_permissions(self, f, compression): - # Make sure that writestr creates files with mode 0600, - # when it is passed a name rather than a ZipInfo instance. + data = b'a\r\n' * 16 * 1024 + with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.writestr(TESTFN, data) - self.make_test_archive(f, compression) - with zipfile.ZipFile(f, "r") as zipfp: - zinfo = zipfp.getinfo('strfile') - self.assertEqual(zinfo.external_attr, 0o600 << 16) - if not isinstance(f, str): - f.close() + data2 = b'' + with zipfile.ZipFile(f, 'r') as zipfp, \ + zipfp.open(TESTFN, 'rU') as zipopen: + for line in zipopen: + data2 += line - def test_writestr_permissions(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED) + self.assertEqual(data, data2.replace(b'\n', b'\r\n')) def test_writestr_extended_local_header_issue1202(self): with zipfile.ZipFile(TESTFN2, 'w') as orig_zip: @@ -690,12 +815,12 @@ with zipfile.ZipFile(TESTFN2, "w") as zipfp: for fpath, fdata in SMALL_TEST_DATA: zipfp.writestr(fpath, fdata) - self.assertTrue(zipfp.fp is not None, 'zipfp is not open') - self.assertTrue(zipfp.fp is None, 'zipfp is not closed') + self.assertIsNotNone(zipfp.fp, 'zipfp is not open') + self.assertIsNone(zipfp.fp, 'zipfp is not closed') with zipfile.ZipFile(TESTFN2, "r") as zipfp: - self.assertTrue(zipfp.fp is not None, 'zipfp is not open') - self.assertTrue(zipfp.fp is None, 'zipfp is not closed') + self.assertIsNotNone(zipfp.fp, 'zipfp is not open') + self.assertIsNone(zipfp.fp, 'zipfp is not closed') def test_close_on_exception(self): """Check that the zipfile is closed if an exception is raised in the @@ -708,317 +833,7 @@ with zipfile.ZipFile(TESTFN2, "r") as zipfp2: raise zipfile.BadZipFile() except zipfile.BadZipFile: - self.assertTrue(zipfp2.fp is None, 'zipfp is not closed') - - def test_add_file_before_1980(self): - # Set atime and mtime to 1970-01-01 - os.utime(TESTFN, (0, 0)) - with zipfile.ZipFile(TESTFN2, "w") as zipfp: - self.assertRaises(ValueError, zipfp.write, TESTFN) - - - - - - - - @requires_zlib - def test_unicode_filenames(self): - # bug #10801 - fname = findfile('zip_cp437_header.zip') - with zipfile.ZipFile(fname) as zipfp: - for name in zipfp.namelist(): - zipfp.open(name).close() - - def tearDown(self): - unlink(TESTFN) - unlink(TESTFN2) - - -class TestZip64InSmallFiles(unittest.TestCase): - # These tests test the ZIP64 functionality without using large files, - # see test_zipfile64 for proper tests. - - def setUp(self): - self._limit = zipfile.ZIP64_LIMIT - zipfile.ZIP64_LIMIT = 5 - - line_gen = (bytes("Test of zipfile line %d." % i, "ascii") - for i in range(0, FIXEDTEST_SIZE)) - self.data = b'\n'.join(line_gen) - - # Make a source file with some lines - with open(TESTFN, "wb") as fp: - fp.write(self.data) - - def large_file_exception_test(self, f, compression): - with zipfile.ZipFile(f, "w", compression) as zipfp: - self.assertRaises(zipfile.LargeZipFile, - zipfp.write, TESTFN, "another.name") - - def large_file_exception_test2(self, f, compression): - with zipfile.ZipFile(f, "w", compression) as zipfp: - self.assertRaises(zipfile.LargeZipFile, - zipfp.writestr, "another.name", self.data) - if not isinstance(f, str): - f.close() - - def test_large_file_exception(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.large_file_exception_test(f, zipfile.ZIP_STORED) - self.large_file_exception_test2(f, zipfile.ZIP_STORED) - - def zip_test(self, f, compression): - # Create the ZIP archive - with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp: - zipfp.write(TESTFN, "another.name") - zipfp.write(TESTFN, TESTFN) - zipfp.writestr("strfile", self.data) - - # Read the ZIP archive - with zipfile.ZipFile(f, "r", compression) as zipfp: - self.assertEqual(zipfp.read(TESTFN), self.data) - self.assertEqual(zipfp.read("another.name"), self.data) - self.assertEqual(zipfp.read("strfile"), self.data) - - # Print the ZIP directory - fp = io.StringIO() - zipfp.printdir(fp) - - directory = fp.getvalue() - lines = directory.splitlines() - self.assertEqual(len(lines), 4) # Number of files + header - - self.assertIn('File Name', lines[0]) - self.assertIn('Modified', lines[0]) - self.assertIn('Size', lines[0]) - - fn, date, time_, size = lines[1].split() - self.assertEqual(fn, 'another.name') - self.assertTrue(time.strptime(date, '%Y-%m-%d')) - self.assertTrue(time.strptime(time_, '%H:%M:%S')) - self.assertEqual(size, str(len(self.data))) - - # Check the namelist - names = zipfp.namelist() - self.assertEqual(len(names), 3) - self.assertIn(TESTFN, names) - self.assertIn("another.name", names) - self.assertIn("strfile", names) - - # Check infolist - infos = zipfp.infolist() - names = [i.filename for i in infos] - self.assertEqual(len(names), 3) - self.assertIn(TESTFN, names) - self.assertIn("another.name", names) - self.assertIn("strfile", names) - for i in infos: - self.assertEqual(i.file_size, len(self.data)) - - # check getinfo - for nm in (TESTFN, "another.name", "strfile"): - info = zipfp.getinfo(nm) - self.assertEqual(info.filename, nm) - self.assertEqual(info.file_size, len(self.data)) - - # Check that testzip doesn't raise an exception - zipfp.testzip() - if not isinstance(f, str): - f.close() - - def test_stored(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_STORED) - - @requires_zlib - def test_deflated(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_bzip2(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_BZIP2) - - @requires_lzma - def test_lzma(self): - for f in (TESTFN2, TemporaryFile(), io.BytesIO()): - self.zip_test(f, zipfile.ZIP_LZMA) - - def test_absolute_arcnames(self): - with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, - allowZip64=True) as zipfp: - zipfp.write(TESTFN, "/absolute") - - with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp: - self.assertEqual(zipfp.namelist(), ["absolute"]) - - def tearDown(self): - zipfile.ZIP64_LIMIT = self._limit - unlink(TESTFN) - unlink(TESTFN2) - - -class PyZipFileTests(unittest.TestCase): - def test_write_pyfile(self): - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - fn = __file__ - if fn.endswith('.pyc') or fn.endswith('.pyo'): - path_split = fn.split(os.sep) - if os.altsep is not None: - path_split.extend(fn.split(os.altsep)) - if '__pycache__' in path_split: - fn = importlib.util.source_from_cache(fn) - else: - fn = fn[:-1] - - zipfp.writepy(fn) - - bn = os.path.basename(fn) - self.assertNotIn(bn, zipfp.namelist()) - self.assertTrue(bn + 'o' in zipfp.namelist() or - bn + 'c' in zipfp.namelist()) - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - fn = __file__ - if fn.endswith(('.pyc', '.pyo')): - fn = fn[:-1] - - zipfp.writepy(fn, "testpackage") - - bn = "%s/%s" % ("testpackage", os.path.basename(fn)) - self.assertNotIn(bn, zipfp.namelist()) - self.assertTrue(bn + 'o' in zipfp.namelist() or - bn + 'c' in zipfp.namelist()) - - def test_write_python_package(self): - import email - packagedir = os.path.dirname(email.__file__) - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - zipfp.writepy(packagedir) - - # Check for a couple of modules at different levels of the - # hierarchy - names = zipfp.namelist() - self.assertTrue('email/__init__.pyo' in names or - 'email/__init__.pyc' in names) - self.assertTrue('email/mime/text.pyo' in names or - 'email/mime/text.pyc' in names) - - def test_write_with_optimization(self): - import email - packagedir = os.path.dirname(email.__file__) - # use .pyc if running test in optimization mode, - # use .pyo if running test in debug mode - optlevel = 1 if __debug__ else 0 - ext = '.pyo' if optlevel == 1 else '.pyc' - - with TemporaryFile() as t, \ - zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp: - zipfp.writepy(packagedir) - - names = zipfp.namelist() - self.assertIn('email/__init__' + ext, names) - self.assertIn('email/mime/text' + ext, names) - - def test_write_python_directory(self): - os.mkdir(TESTFN2) - try: - with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: - fp.write("print(42)\n") - - with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp: - fp.write("print(42 * 42)\n") - - with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp: - fp.write("bla bla bla\n") - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - zipfp.writepy(TESTFN2) - - names = zipfp.namelist() - self.assertTrue('mod1.pyc' in names or 'mod1.pyo' in names) - self.assertTrue('mod2.pyc' in names or 'mod2.pyo' in names) - self.assertNotIn('mod2.txt', names) - - finally: - shutil.rmtree(TESTFN2) - - def test_write_non_pyfile(self): - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - with open(TESTFN, 'w') as f: - f.write('most definitely not a python file') - self.assertRaises(RuntimeError, zipfp.writepy, TESTFN) - os.remove(TESTFN) - - def test_write_pyfile_bad_syntax(self): - os.mkdir(TESTFN2) - try: - with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: - fp.write("Bad syntax in python file\n") - - with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: - # syntax errors are printed to stdout - with captured_stdout() as s: - zipfp.writepy(os.path.join(TESTFN2, "mod1.py")) - - self.assertIn("SyntaxError", s.getvalue()) - - # as it will not have compiled the python file, it will - # include the .py file not .pyc or .pyo - names = zipfp.namelist() - self.assertIn('mod1.py', names) - self.assertNotIn('mod1.pyc', names) - self.assertNotIn('mod1.pyo', names) - - finally: - shutil.rmtree(TESTFN2) - -class OtherTests(unittest.TestCase): - zips_with_bad_crc = { - zipfile.ZIP_STORED: ( - b'PK\003\004\024\0\0\0\0\0 \213\212;:r' - b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af' - b'ilehello,AworldP' - b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:' - b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0' - b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi' - b'lePK\005\006\0\0\0\0\001\0\001\0003\000' - b'\0\0/\0\0\0\0\0'), - zipfile.ZIP_DEFLATED: ( - b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA' - b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' - b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0' - b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n' - b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00' - b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00' - b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00'), - zipfile.ZIP_BZIP2: ( - b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA' - b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' - b'ileBZh91AY&SY\xd4\xa8\xca' - b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5' - b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f' - b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14' - b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8' - b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK' - b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00' - b'\x00\x00\x00\x00'), - zipfile.ZIP_LZMA: ( - b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA' - b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' - b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I' - b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK' - b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA' - b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil' - b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00' - b'\x00>\x00\x00\x00\x00\x00'), - } + self.assertIsNone(zipfp2.fp, 'zipfp is not closed') def test_unsupported_version(self): # File has an extract_version of 120 @@ -1027,10 +842,19 @@ b'\x00!p\xa1@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00xPK\x05\x06' b'\x00\x00\x00\x00\x01\x00\x01\x00/\x00\x00\x00\x1f\x00\x00\x00\x00\x00') + self.assertRaises(NotImplementedError, zipfile.ZipFile, io.BytesIO(data), 'r') - def test_unicode_filenames(self): + @requires_zlib + def test_read_unicode_filenames(self): + # bug #10801 + fname = findfile('zip_cp437_header.zip') + with zipfile.ZipFile(fname) as zipfp: + for name in zipfp.namelist(): + zipfp.open(name).close() + + def test_write_unicode_filenames(self): with zipfile.ZipFile(TESTFN, "w") as zf: zf.writestr("foo.txt", "Test for unicode filename") zf.writestr("\xf6.txt", "Test for unicode filename") @@ -1078,20 +902,16 @@ # - passing a filename with open(TESTFN, "w") as fp: fp.write("this is not a legal zip file\n") - chk = zipfile.is_zipfile(TESTFN) - self.assertFalse(chk) + self.assertFalse(zipfile.is_zipfile(TESTFN)) # - passing a file object with open(TESTFN, "rb") as fp: - chk = zipfile.is_zipfile(fp) - self.assertTrue(not chk) + self.assertFalse(zipfile.is_zipfile(fp)) # - passing a file-like object fp = io.BytesIO() fp.write(b"this is not a legal zip file\n") - chk = zipfile.is_zipfile(fp) - self.assertTrue(not chk) + self.assertFalse(zipfile.is_zipfile(fp)) fp.seek(0, 0) - chk = zipfile.is_zipfile(fp) - self.assertTrue(not chk) + self.assertFalse(zipfile.is_zipfile(fp)) def test_damaged_zipfile(self): """Check that zipfiles with missing bytes at the end raise BadZipFile.""" @@ -1113,22 +933,18 @@ with zipfile.ZipFile(TESTFN, mode="w") as zipf: zipf.writestr("foo.txt", b"O, for a Muse of Fire!") - chk = zipfile.is_zipfile(TESTFN) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(TESTFN)) # - passing a file object with open(TESTFN, "rb") as fp: - chk = zipfile.is_zipfile(fp) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(fp)) fp.seek(0, 0) zip_contents = fp.read() # - passing a file-like object fp = io.BytesIO() fp.write(zip_contents) - chk = zipfile.is_zipfile(fp) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(fp)) fp.seek(0, 0) - chk = zipfile.is_zipfile(fp) - self.assertTrue(chk) + self.assertTrue(zipfile.is_zipfile(fp)) def test_non_existent_file_raises_OSError(self): # make sure we don't raise an AttributeError when a partially-constructed @@ -1309,93 +1125,6 @@ with zipfile.ZipFile(TESTFN, "r") as zipf: self.assertEqual(zipf.comment, b"this is a comment") - def check_testzip_with_bad_crc(self, compression): - """Tests that files with bad CRCs return their name from testzip.""" - zipdata = self.zips_with_bad_crc[compression] - - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - # testzip returns the name of the first corrupt file, or None - self.assertEqual('afile', zipf.testzip()) - - def test_testzip_with_bad_crc_stored(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_STORED) - - @requires_zlib - def test_testzip_with_bad_crc_deflated(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_testzip_with_bad_crc_bzip2(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_BZIP2) - - @requires_lzma - def test_testzip_with_bad_crc_lzma(self): - self.check_testzip_with_bad_crc(zipfile.ZIP_LZMA) - - def check_read_with_bad_crc(self, compression): - """Tests that files with bad CRCs raise a BadZipFile exception when read.""" - zipdata = self.zips_with_bad_crc[compression] - - # Using ZipFile.read() - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile') - - # Using ZipExtFile.read() - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - with zipf.open('afile', 'r') as corrupt_file: - self.assertRaises(zipfile.BadZipFile, corrupt_file.read) - - # Same with small reads (in order to exercise the buffering logic) - with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: - with zipf.open('afile', 'r') as corrupt_file: - corrupt_file.MIN_READ_SIZE = 2 - with self.assertRaises(zipfile.BadZipFile): - while corrupt_file.read(2): - pass - - def test_read_with_bad_crc_stored(self): - self.check_read_with_bad_crc(zipfile.ZIP_STORED) - - @requires_zlib - def test_read_with_bad_crc_deflated(self): - self.check_read_with_bad_crc(zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_read_with_bad_crc_bzip2(self): - self.check_read_with_bad_crc(zipfile.ZIP_BZIP2) - - @requires_lzma - def test_read_with_bad_crc_lzma(self): - self.check_read_with_bad_crc(zipfile.ZIP_LZMA) - - def check_read_return_size(self, compression): - # Issue #9837: ZipExtFile.read() shouldn't return more bytes - # than requested. - for test_size in (1, 4095, 4096, 4097, 16384): - file_size = test_size + 1 - junk = b''.join(struct.pack('B', randint(0, 255)) - for x in range(file_size)) - with zipfile.ZipFile(io.BytesIO(), "w", compression) as zipf: - zipf.writestr('foo', junk) - with zipf.open('foo', 'r') as fp: - buf = fp.read(test_size) - self.assertEqual(len(buf), test_size) - - def test_read_return_size_stored(self): - self.check_read_return_size(zipfile.ZIP_STORED) - - @requires_zlib - def test_read_return_size_deflated(self): - self.check_read_return_size(zipfile.ZIP_DEFLATED) - - @requires_bz2 - def test_read_return_size_bzip2(self): - self.check_read_return_size(zipfile.ZIP_BZIP2) - - @requires_lzma - def test_read_return_size_lzma(self): - self.check_read_return_size(zipfile.ZIP_LZMA) - def test_empty_zipfile(self): # Check that creating a file in 'w' or 'a' mode and closing without # adding any files to the archives creates a valid empty ZIP file @@ -1430,6 +1159,93 @@ unlink(TESTFN2) +class AbstractBadCrcTests: + def test_testzip_with_bad_crc(self): + """Tests that files with bad CRCs return their name from testzip.""" + zipdata = self.zip_with_bad_crc + + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + # testzip returns the name of the first corrupt file, or None + self.assertEqual('afile', zipf.testzip()) + + def test_read_with_bad_crc(self): + """Tests that files with bad CRCs raise a BadZipFile exception when read.""" + zipdata = self.zip_with_bad_crc + + # Using ZipFile.read() + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile') + + # Using ZipExtFile.read() + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + with zipf.open('afile', 'r') as corrupt_file: + self.assertRaises(zipfile.BadZipFile, corrupt_file.read) + + # Same with small reads (in order to exercise the buffering logic) + with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf: + with zipf.open('afile', 'r') as corrupt_file: + corrupt_file.MIN_READ_SIZE = 2 + with self.assertRaises(zipfile.BadZipFile): + while corrupt_file.read(2): + pass + + +class StoredBadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_STORED + zip_with_bad_crc = ( + b'PK\003\004\024\0\0\0\0\0 \213\212;:r' + b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af' + b'ilehello,AworldP' + b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:' + b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0' + b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi' + b'lePK\005\006\0\0\0\0\001\0\001\0003\000' + b'\0\0/\0\0\0\0\0') + + at requires_zlib +class DeflateBadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_DEFLATED + zip_with_bad_crc = ( + b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA' + b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' + b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0' + b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n' + b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05' + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00' + b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00' + b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00') + + at requires_bz2 +class Bzip2BadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_BZIP2 + zip_with_bad_crc = ( + b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA' + b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' + b'ileBZh91AY&SY\xd4\xa8\xca' + b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5' + b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f' + b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14' + b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8' + b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK' + b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00' + b'\x00\x00\x00\x00') + + at requires_lzma +class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase): + compression = zipfile.ZIP_LZMA + zip_with_bad_crc = ( + b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA' + b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af' + b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I' + b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK' + b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA' + b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil' + b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00' + b'\x00>\x00\x00\x00\x00\x00') + + class DecryptionTests(unittest.TestCase): """Check that ZIP decryption works. Since the library does not support encryption at the moment, we use a pre-generated encrypted @@ -1495,13 +1311,14 @@ self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python") self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python") +class AbstractTestsWithRandomBinaryFiles: + @classmethod + def setUpClass(cls): + datacount = randint(16, 64)*1024 + randint(1, 1024) + cls.data = b''.join(struct.pack(' http://hg.python.org/cpython/rev/fc718c177ee6 changeset: 84793:fc718c177ee6 user: Victor Stinner date: Mon Jul 22 22:24:54 2013 +0200 summary: Issue #18520: Add a new PyStructSequence_InitType2() function, same than PyStructSequence_InitType() except that it has a return value (0 on success, -1 on error). * PyStructSequence_InitType2() now raises MemoryError on memory allocation failure * Fix also some calls to PyDict_SetItemString(): handle error files: Include/pythonrun.h | 2 +- Include/structseq.h | 2 + Misc/NEWS | 4 +++ Modules/_lsprof.c | 10 ++++--- Modules/grpmodule.c | 11 ++++++-- Modules/posixmodule.c | 24 ++++++++++++------ Modules/pwdmodule.c | 5 ++- Modules/resource.c | 9 ++++-- Modules/signalmodule.c | 7 +++-- Modules/spwdmodule.c | 8 ++++-- Modules/timemodule.c | 5 ++- Objects/floatobject.c | 9 ++++-- Objects/longobject.c | 6 +++- Objects/structseq.c | 37 +++++++++++++++++++++-------- Python/pythonrun.c | 3 +- Python/sysmodule.c | 23 ++++++++++++----- Python/thread.c | 6 +++- 17 files changed, 117 insertions(+), 54 deletions(-) diff --git a/Include/pythonrun.h b/Include/pythonrun.h --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -197,7 +197,7 @@ PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod); PyAPI_FUNC(void) _PyImportHooks_Init(void); PyAPI_FUNC(int) _PyFrame_Init(void); -PyAPI_FUNC(void) _PyFloat_Init(void); +PyAPI_FUNC(int) _PyFloat_Init(void); PyAPI_FUNC(int) PyByteArray_Init(void); PyAPI_FUNC(void) _PyRandom_Init(void); #endif diff --git a/Include/structseq.h b/Include/structseq.h --- a/Include/structseq.h +++ b/Include/structseq.h @@ -24,6 +24,8 @@ #ifndef Py_LIMITED_API PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc); +PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type, + PyStructSequence_Desc *desc); #endif PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc); diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #18520: Add a new PyStructSequence_InitType2() function, same than + PyStructSequence_InitType() except that it has a return value (0 on success, + -1 on error). + - Issue #15905: Fix theoretical buffer overflow in handling of sys.argv[0], prefix and exec_prefix if the operation system does not obey MAXPATHLEN. diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -884,10 +884,12 @@ PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type); if (!initialized) { - PyStructSequence_InitType(&StatsEntryType, - &profiler_entry_desc); - PyStructSequence_InitType(&StatsSubEntryType, - &profiler_subentry_desc); + if (PyStructSequence_InitType2(&StatsEntryType, + &profiler_entry_desc) < 0) + return NULL; + if (PyStructSequence_InitType2(&StatsSubEntryType, + &profiler_subentry_desc) < 0) + return NULL; } Py_INCREF((PyObject*) &StatsEntryType); Py_INCREF((PyObject*) &StatsSubEntryType); diff --git a/Modules/grpmodule.c b/Modules/grpmodule.c --- a/Modules/grpmodule.c +++ b/Modules/grpmodule.c @@ -210,9 +210,14 @@ if (m == NULL) return NULL; d = PyModule_GetDict(m); - if (!initialized) - PyStructSequence_InitType(&StructGrpType, &struct_group_type_desc); - PyDict_SetItemString(d, "struct_group", (PyObject *) &StructGrpType); + if (!initialized) { + if (PyStructSequence_InitType2(&StructGrpType, + &struct_group_type_desc) < 0) + return NULL; + } + if (PyDict_SetItemString(d, "struct_group", + (PyObject *)&StructGrpType) < 0) + return NULL; initialized = 1; return m; } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -11518,19 +11518,23 @@ if (!initialized) { #if defined(HAVE_WAITID) && !defined(__APPLE__) waitid_result_desc.name = MODNAME ".waitid_result"; - PyStructSequence_InitType(&WaitidResultType, &waitid_result_desc); + if (PyStructSequence_InitType2(&WaitidResultType, &waitid_result_desc) < 0) + return NULL; #endif stat_result_desc.name = MODNAME ".stat_result"; stat_result_desc.fields[7].name = PyStructSequence_UnnamedField; stat_result_desc.fields[8].name = PyStructSequence_UnnamedField; stat_result_desc.fields[9].name = PyStructSequence_UnnamedField; - PyStructSequence_InitType(&StatResultType, &stat_result_desc); + if (PyStructSequence_InitType2(&StatResultType, &stat_result_desc) < 0) + return NULL; structseq_new = StatResultType.tp_new; StatResultType.tp_new = statresult_new; statvfs_result_desc.name = MODNAME ".statvfs_result"; - PyStructSequence_InitType(&StatVFSResultType, &statvfs_result_desc); + if (PyStructSequence_InitType2(&StatVFSResultType, + &statvfs_result_desc) < 0) + return NULL; #ifdef NEED_TICKS_PER_SECOND # if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) ticks_per_second = sysconf(_SC_CLK_TCK); @@ -11543,12 +11547,15 @@ #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) sched_param_desc.name = MODNAME ".sched_param"; - PyStructSequence_InitType(&SchedParamType, &sched_param_desc); + if (PyStructSequence_InitType2(&SchedParamType, &sched_param_desc) < 0) + return NULL; SchedParamType.tp_new = sched_param_new; #endif /* initialize TerminalSize_info */ - PyStructSequence_InitType(&TerminalSizeType, &TerminalSize_desc); + if (PyStructSequence_InitType2(&TerminalSizeType, + &TerminalSize_desc) < 0) + return NULL; } #if defined(HAVE_WAITID) && !defined(__APPLE__) Py_INCREF((PyObject*) &WaitidResultType); @@ -11566,11 +11573,13 @@ #endif times_result_desc.name = MODNAME ".times_result"; - PyStructSequence_InitType(&TimesResultType, ×_result_desc); + if (PyStructSequence_InitType2(&TimesResultType, ×_result_desc) < 0) + return NULL; PyModule_AddObject(m, "times_result", (PyObject *)&TimesResultType); uname_result_desc.name = MODNAME ".uname_result"; - PyStructSequence_InitType(&UnameResultType, &uname_result_desc); + if (PyStructSequence_InitType2(&UnameResultType, &uname_result_desc) < 0) + return NULL; PyModule_AddObject(m, "uname_result", (PyObject *)&UnameResultType); #ifdef __APPLE__ @@ -11648,7 +11657,6 @@ initialized = 1; return m; - } #ifdef __cplusplus diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c --- a/Modules/pwdmodule.c +++ b/Modules/pwdmodule.c @@ -216,8 +216,9 @@ return NULL; if (!initialized) { - PyStructSequence_InitType(&StructPwdType, - &struct_pwd_type_desc); + if (PyStructSequence_InitType2(&StructPwdType, + &struct_pwd_type_desc) < 0) + return NULL; initialized = 1; } Py_INCREF((PyObject *) &StructPwdType); diff --git a/Modules/resource.c b/Modules/resource.c --- a/Modules/resource.c +++ b/Modules/resource.c @@ -263,9 +263,12 @@ /* Add some symbolic constants to the module */ Py_INCREF(PyExc_OSError); PyModule_AddObject(m, "error", PyExc_OSError); - if (!initialized) - PyStructSequence_InitType(&StructRUsageType, - &struct_rusage_desc); + if (!initialized) { + if (PyStructSequence_InitType2(&StructRUsageType, + &struct_rusage_desc) < 0) + return NULL; + } + Py_INCREF(&StructRUsageType); PyModule_AddObject(m, "struct_rusage", (PyObject*) &StructRUsageType); diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -978,9 +978,10 @@ return NULL; #if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT) - if (!initialized) - PyStructSequence_InitType(&SiginfoType, &struct_siginfo_desc); - + if (!initialized) { + if (PyStructSequence_InitType2(&SiginfoType, &struct_siginfo_desc) < 0) + return NULL; + } Py_INCREF((PyObject*) &SiginfoType); PyModule_AddObject(m, "struct_siginfo", (PyObject*) &SiginfoType); initialized = 1; diff --git a/Modules/spwdmodule.c b/Modules/spwdmodule.c --- a/Modules/spwdmodule.c +++ b/Modules/spwdmodule.c @@ -196,9 +196,11 @@ m=PyModule_Create(&spwdmodule); if (m == NULL) return NULL; - if (!initialized) - PyStructSequence_InitType(&StructSpwdType, - &struct_spwd_type_desc); + if (!initialized) { + if (PyStructSequence_InitType2(&StructSpwdType, + &struct_spwd_type_desc) < 0) + return NULL; + } Py_INCREF((PyObject *) &StructSpwdType); PyModule_AddObject(m, "struct_spwd", (PyObject *) &StructSpwdType); initialized = 1; diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1476,8 +1476,9 @@ PyInit_timezone(m); if (!initialized) { - PyStructSequence_InitType(&StructTimeType, - &struct_time_type_desc); + if (PyStructSequence_InitType2(&StructTimeType, + &struct_time_type_desc) < 0) + return NULL; #ifdef MS_WINDOWS winver.dwOSVersionInfoSize = sizeof(winver); diff --git a/Objects/floatobject.c b/Objects/floatobject.c --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1853,7 +1853,7 @@ float_new, /* tp_new */ }; -void +int _PyFloat_Init(void) { /* We attempt to determine if this machine is using IEEE @@ -1903,8 +1903,11 @@ float_format = detected_float_format; /* Init float info */ - if (FloatInfoType.tp_name == 0) - PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc); + if (FloatInfoType.tp_name == NULL) { + if (PyStructSequence_InitType2(&FloatInfoType, &floatinfo_desc) < 0) + return 0; + } + return 1; } int diff --git a/Objects/longobject.c b/Objects/longobject.c --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5059,8 +5059,10 @@ } #endif /* initialize int_info */ - if (Int_InfoType.tp_name == 0) - PyStructSequence_InitType(&Int_InfoType, &int_info_desc); + if (Int_InfoType.tp_name == NULL) { + if (PyStructSequence_InitType2(&Int_InfoType, &int_info_desc) < 0) + return 0; + } return 1; } diff --git a/Objects/structseq.c b/Objects/structseq.c --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -320,12 +320,13 @@ structseq_new, /* tp_new */ }; -void -PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) +int +PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) { PyObject *dict; PyMemberDef* members; int n_members, n_unnamed_members, i, k; + PyObject *v; #ifdef Py_TRACE_REFS /* if the type object was chained, unchain it first @@ -347,8 +348,10 @@ type->tp_doc = desc->doc; members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1); - if (members == NULL) - return; + if (members == NULL) { + PyErr_NoMemory(); + return -1; + } for (i = k = 0; i < n_members; ++i) { if (desc->fields[i].name == PyStructSequence_UnnamedField) @@ -366,22 +369,33 @@ type->tp_members = members; if (PyType_Ready(type) < 0) - return; + return -1; Py_INCREF(type); dict = type->tp_dict; #define SET_DICT_FROM_INT(key, value) \ do { \ - PyObject *v = PyLong_FromLong((long) value); \ - if (v != NULL) { \ - PyDict_SetItemString(dict, key, v); \ + v = PyLong_FromLong((long) value); \ + if (v == NULL) \ + return -1; \ + if (PyDict_SetItemString(dict, key, v) < 0) { \ Py_DECREF(v); \ + return -1; \ } \ + Py_DECREF(v); \ } while (0) SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence); SET_DICT_FROM_INT(real_length_key, n_members); SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members); + + return 0; +} + +void +PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) +{ + (void)PyStructSequence_InitType2(type, desc); } PyTypeObject* @@ -390,8 +404,11 @@ PyTypeObject *result; result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); - if (result != NULL) { - PyStructSequence_InitType(result, desc); + if (result == NULL) + return NULL; + if (PyStructSequence_InitType2(result, desc) < 0) { + Py_DECREF(result); + return NULL; } return result; } diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -328,7 +328,8 @@ if (!PyByteArray_Init()) Py_FatalError("Py_Initialize: can't init bytearray"); - _PyFloat_Init(); + if (!_PyFloat_Init()) + Py_FatalError("Py_Initialize: can't init float"); interp->modules = PyDict_New(); if (interp->modules == NULL) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1634,8 +1634,10 @@ SET_SYS_FROM_STRING("int_info", PyLong_GetInfo()); /* initialize hash_info */ - if (Hash_InfoType.tp_name == 0) - PyStructSequence_InitType(&Hash_InfoType, &hash_info_desc); + if (Hash_InfoType.tp_name == NULL) { + if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < 0) + return NULL; + } SET_SYS_FROM_STRING("hash_info", get_hash_info()); SET_SYS_FROM_STRING("maxunicode", @@ -1676,8 +1678,11 @@ } /* version_info */ - if (VersionInfoType.tp_name == 0) - PyStructSequence_InitType(&VersionInfoType, &version_info_desc); + if (VersionInfoType.tp_name == NULL) { + if (PyStructSequence_InitType2(&VersionInfoType, + &version_info_desc) < 0) + return NULL; + } version_info = make_version_info(); SET_SYS_FROM_STRING("version_info", version_info); /* prevent user from creating new instances */ @@ -1688,8 +1693,10 @@ SET_SYS_FROM_STRING("implementation", make_impl_info(version_info)); /* flags */ - if (FlagsType.tp_name == 0) - PyStructSequence_InitType(&FlagsType, &flags_desc); + if (FlagsType.tp_name == 0) { + if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0) + return NULL; + } SET_SYS_FROM_STRING("flags", make_flags()); /* prevent user from creating new instances */ FlagsType.tp_init = NULL; @@ -1699,7 +1706,9 @@ #if defined(MS_WINDOWS) /* getwindowsversion */ if (WindowsVersionType.tp_name == 0) - PyStructSequence_InitType(&WindowsVersionType, &windows_version_desc); + if (PyStructSequence_InitType2(&WindowsVersionType, + &windows_version_desc) < 0) + return NULL; /* prevent user from creating new instances */ WindowsVersionType.tp_init = NULL; WindowsVersionType.tp_new = NULL; diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -399,8 +399,10 @@ int len; #endif - if (ThreadInfoType.tp_name == 0) - PyStructSequence_InitType(&ThreadInfoType, &threadinfo_desc); + if (ThreadInfoType.tp_name == 0) { + if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0) + return NULL; + } threadinfo = PyStructSequence_New(&ThreadInfoType); if (threadinfo == NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 23:59:08 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 22 Jul 2013 23:59:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318520=3A_PyErr=5F?= =?utf-8?q?NoMemory=28=29_now_fails_with_a_fatal_error_if_it_is_called?= Message-ID: <3bzcCw1w4jz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/9b77b3ee6fb8 changeset: 84794:9b77b3ee6fb8 user: Victor Stinner date: Mon Jul 22 22:28:37 2013 +0200 summary: Issue #18520: PyErr_NoMemory() now fails with a fatal error if it is called before PyExc_MemoryError has been initialized by _PyExc_Init() files: Python/errors.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -380,6 +380,12 @@ PyObject * PyErr_NoMemory(void) { + if (Py_TYPE(PyExc_MemoryError) == NULL) { + /* PyErr_NoMemory() has been called before PyExc_MemoryError has been + initialized by _PyExc_Init() */ + Py_FatalError("Out of memory and PyExc_MemoryError is not " + "initialized yet"); + } PyErr_SetNone(PyExc_MemoryError); return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 23:59:09 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 22 Jul 2013 23:59:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318520=3A_Fix_=5FP?= =?utf-8?q?ySys=5FInit=28=29=2C_handle_PyDict=5FSetItemString=28=29_errors?= Message-ID: <3bzcCx4rrfz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/31796b188bec changeset: 84795:31796b188bec user: Victor Stinner date: Mon Jul 22 22:40:00 2013 +0200 summary: Issue #18520: Fix _PySys_Init(), handle PyDict_SetItemString() errors files: Python/sysmodule.c | 38 ++++++++++++++++++--------------- 1 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1565,17 +1565,24 @@ PyObject * _PySys_Init(void) { - PyObject *m, *v, *sysdict, *version_info; + PyObject *m, *sysdict, *version_info; m = PyModule_Create(&sysmodule); if (m == NULL) return NULL; sysdict = PyModule_GetDict(m); -#define SET_SYS_FROM_STRING(key, value) \ - v = value; \ - if (v != NULL) \ - PyDict_SetItemString(sysdict, key, v); \ - Py_XDECREF(v) +#define SET_SYS_FROM_STRING(key, value) \ + do { \ + int res; \ + PyObject *v = (value); \ + if (v == NULL) \ + return NULL; \ + res = PyDict_SetItemString(sysdict, key, v); \ + if (res < 0) { \ + Py_DECREF(v); \ + return NULL; \ + } \ + } while (0) /* Check that stdin is not a directory Using shell redirection, you can redirect stdin to a directory, @@ -1597,10 +1604,10 @@ /* stdin/stdout/stderr are now set by pythonrun.c */ - PyDict_SetItemString(sysdict, "__displayhook__", - PyDict_GetItemString(sysdict, "displayhook")); - PyDict_SetItemString(sysdict, "__excepthook__", - PyDict_GetItemString(sysdict, "excepthook")); + SET_SYS_FROM_STRING("__displayhook__", + PyDict_GetItemString(sysdict, "displayhook")); + SET_SYS_FROM_STRING("__excepthook__", + PyDict_GetItemString(sysdict, "excepthook")); SET_SYS_FROM_STRING("version", PyUnicode_FromString(Py_GetVersion())); SET_SYS_FROM_STRING("hexversion", @@ -1664,18 +1671,15 @@ #endif if (warnoptions == NULL) { warnoptions = PyList_New(0); + if (warnoptions == NULL) + return NULL; } else { Py_INCREF(warnoptions); } - if (warnoptions != NULL) { - PyDict_SetItemString(sysdict, "warnoptions", warnoptions); - } + SET_SYS_FROM_STRING("warnoptions", warnoptions); - v = get_xoptions(); - if (v != NULL) { - PyDict_SetItemString(sysdict, "_xoptions", v); - } + SET_SYS_FROM_STRING("_xoptions", get_xoptions()); /* version_info */ if (VersionInfoType.tp_name == NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 23:59:10 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 22 Jul 2013 23:59:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318520=3A_initsite?= =?utf-8?q?=28=29_is_a_little_bit_more_verbose_when_import_site_fails?= Message-ID: <3bzcCy6pYRz7LkD@mail.python.org> http://hg.python.org/cpython/rev/d38348173c46 changeset: 84796:d38348173c46 user: Victor Stinner date: Mon Jul 22 22:53:28 2013 +0200 summary: Issue #18520: initsite() is a little bit more verbose when import site fails files: Python/pythonrun.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -918,6 +918,7 @@ PyObject *m; m = PyImport_ImportModule("site"); if (m == NULL) { + fprintf(stderr, "Failed to import the site module\n"); PyErr_Print(); Py_Finalize(); exit(1); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 23:59:12 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 22 Jul 2013 23:59:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Reindent_PyFunction=5FNewW?= =?utf-8?q?ithQualName=28=29?= Message-ID: <3bzcD02ZgJz7LkZ@mail.python.org> http://hg.python.org/cpython/rev/b20bc1aa5686 changeset: 84797:b20bc1aa5686 user: Victor Stinner date: Mon Jul 22 23:02:05 2013 +0200 summary: Reindent PyFunction_NewWithQualName() files: Objects/funcobject.c | 102 +++++++++++++++--------------- 1 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Objects/funcobject.c b/Objects/funcobject.c --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -8,60 +8,60 @@ PyObject * PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname) { - PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, - &PyFunction_Type); - static PyObject *__name__ = 0; - if (op != NULL) { - PyObject *doc; - PyObject *consts; - PyObject *module; - op->func_weakreflist = NULL; - Py_INCREF(code); - op->func_code = code; - Py_INCREF(globals); - op->func_globals = globals; - op->func_name = ((PyCodeObject *)code)->co_name; - Py_INCREF(op->func_name); - op->func_defaults = NULL; /* No default arguments */ - op->func_kwdefaults = NULL; /* No keyword only defaults */ - op->func_closure = NULL; - consts = ((PyCodeObject *)code)->co_consts; - if (PyTuple_Size(consts) >= 1) { - doc = PyTuple_GetItem(consts, 0); - if (!PyUnicode_Check(doc)) - doc = Py_None; - } - else + PyFunctionObject *op; + PyObject *doc, *consts, *module; + static PyObject *__name__ = NULL; + + op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type); + if (op == NULL) + return NULL; + + op->func_weakreflist = NULL; + Py_INCREF(code); + op->func_code = code; + Py_INCREF(globals); + op->func_globals = globals; + op->func_name = ((PyCodeObject *)code)->co_name; + Py_INCREF(op->func_name); + op->func_defaults = NULL; /* No default arguments */ + op->func_kwdefaults = NULL; /* No keyword only defaults */ + op->func_closure = NULL; + consts = ((PyCodeObject *)code)->co_consts; + if (PyTuple_Size(consts) >= 1) { + doc = PyTuple_GetItem(consts, 0); + if (!PyUnicode_Check(doc)) doc = Py_None; - Py_INCREF(doc); - op->func_doc = doc; - op->func_dict = NULL; - op->func_module = NULL; - op->func_annotations = NULL; - - /* __module__: If module name is in globals, use it. - Otherwise, use None. - */ - if (!__name__) { - __name__ = PyUnicode_InternFromString("__name__"); - if (!__name__) { - Py_DECREF(op); - return NULL; - } - } - module = PyDict_GetItem(globals, __name__); - if (module) { - Py_INCREF(module); - op->func_module = module; - } - if (qualname) - op->func_qualname = qualname; - else - op->func_qualname = op->func_name; - Py_INCREF(op->func_qualname); } else - return NULL; + doc = Py_None; + Py_INCREF(doc); + op->func_doc = doc; + op->func_dict = NULL; + op->func_module = NULL; + op->func_annotations = NULL; + + /* __module__: If module name is in globals, use it. + Otherwise, use None. + */ + if (!__name__) { + __name__ = PyUnicode_InternFromString("__name__"); + if (!__name__) { + Py_DECREF(op); + return NULL; + } + } + + module = PyDict_GetItem(globals, __name__); + if (module) { + Py_INCREF(module); + op->func_module = module; + } + if (qualname) + op->func_qualname = qualname; + else + op->func_qualname = op->func_name; + Py_INCREF(op->func_qualname); + _PyObject_GC_TRACK(op); return (PyObject *)op; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 23:59:13 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 22 Jul 2013 23:59:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318520=3A_Fix_PyFu?= =?utf-8?q?nction=5FNewWithQualName=28=29_error_handling?= Message-ID: <3bzcD159Mlz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/9267a0b836b7 changeset: 84798:9267a0b836b7 user: Victor Stinner date: Mon Jul 22 23:04:55 2013 +0200 summary: Issue #18520: Fix PyFunction_NewWithQualName() error handling files: Objects/funcobject.c | 19 +++++++++---------- 1 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Objects/funcobject.c b/Objects/funcobject.c --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -12,6 +12,12 @@ PyObject *doc, *consts, *module; static PyObject *__name__ = NULL; + if (__name__ == NULL) { + __name__ = PyUnicode_InternFromString("__name__"); + if (__name__ == NULL) + return NULL; + } + op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type); if (op == NULL) return NULL; @@ -26,6 +32,7 @@ op->func_defaults = NULL; /* No default arguments */ op->func_kwdefaults = NULL; /* No keyword only defaults */ op->func_closure = NULL; + consts = ((PyCodeObject *)code)->co_consts; if (PyTuple_Size(consts) >= 1) { doc = PyTuple_GetItem(consts, 0); @@ -36,21 +43,13 @@ doc = Py_None; Py_INCREF(doc); op->func_doc = doc; + op->func_dict = NULL; op->func_module = NULL; op->func_annotations = NULL; /* __module__: If module name is in globals, use it. - Otherwise, use None. - */ - if (!__name__) { - __name__ = PyUnicode_InternFromString("__name__"); - if (!__name__) { - Py_DECREF(op); - return NULL; - } - } - + Otherwise, use None. */ module = PyDict_GetItem(globals, __name__); if (module) { Py_INCREF(module); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 23:59:14 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 22 Jul 2013 23:59:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318520=3A_Fix_=5FP?= =?utf-8?q?yDict=5FGetItemId=28=29=2C_suppress_=5FPyUnicode=5FFromId=28=29?= =?utf-8?q?_error?= Message-ID: <3bzcD273lKz7Lkn@mail.python.org> http://hg.python.org/cpython/rev/4a69dbe71aeb changeset: 84799:4a69dbe71aeb user: Victor Stinner date: Mon Jul 22 23:50:57 2013 +0200 summary: Issue #18520: Fix _PyDict_GetItemId(), suppress _PyUnicode_FromId() error As PyDict_GetItem(), _PyDict_GetItemId() suppresses all errors that may occur, for historical reasons. files: Objects/dictobject.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2684,8 +2684,10 @@ { PyObject *kv; kv = _PyUnicode_FromId(key); /* borrowed */ - if (kv == NULL) + if (kv == NULL) { + PyErr_Clear(); return NULL; + } return PyDict_GetItem(dp, kv); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 22 23:59:16 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 22 Jul 2013 23:59:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318520=3A_Fix_init?= =?utf-8?q?stdio=28=29=2C_handle_PySys=5FSetObject=28=29_failure?= Message-ID: <3bzcD41xF8z7LkV@mail.python.org> http://hg.python.org/cpython/rev/a4998e8fd7fc changeset: 84800:a4998e8fd7fc user: Victor Stinner date: Mon Jul 22 23:55:19 2013 +0200 summary: Issue #18520: Fix initstdio(), handle PySys_SetObject() failure files: Python/pythonrun.c | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1159,8 +1159,14 @@ } PyErr_Clear(); /* Not a fatal error if codec isn't available */ - PySys_SetObject("__stderr__", std); - PySys_SetObject("stderr", std); + if (PySys_SetObject("__stderr__", std) < 0) { + Py_DECREF(std); + goto error; + } + if (PySys_SetObject("stderr", std) < 0) { + Py_DECREF(std); + goto error; + } Py_DECREF(std); #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 23 01:31:24 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 23 Jul 2013 01:31:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_modeling_file_for_Cove?= =?utf-8?q?rity_Scan=2E?= Message-ID: <3bzfGN573Hz7Lkf@mail.python.org> http://hg.python.org/cpython/rev/57d0cce08fb6 changeset: 84801:57d0cce08fb6 user: Christian Heimes date: Tue Jul 23 01:31:15 2013 +0200 summary: Add modeling file for Coverity Scan. The modeling file avoids false positive reports. files: Misc/coverity_model.c | 112 ++++++++++++++++++++++++++++++ 1 files changed, 112 insertions(+), 0 deletions(-) diff --git a/Misc/coverity_model.c b/Misc/coverity_model.c new file mode 100644 --- /dev/null +++ b/Misc/coverity_model.c @@ -0,0 +1,112 @@ +/* Coverity Scan model + * + * This is a modeling file for Coverity Scan. Modeling helps to avoid false + * positives. + * + * - A model file can't import any header files. + * - Therefore only some built-in primitives like int, char and void are + * available but not wchar_t, NULL etc. + * - Modeling doesn't need full structs and typedefs. Rudimentary structs + * and similar types are sufficient. + * - An uninitialized local pointer is not an error. It signifies that the + * variable could be either NULL or have some data. + * + * Coverity Scan doesn't pick up modifications automatically. The model file + * must be uploaded by an admin in the analysis settings of + * http://scan.coverity.com/projects/200 + * + */ + + +/* dummy definitions, in most cases struct fields aren't required. */ + +#define NULL (void *)0 + +typedef int sdigit; +typedef long Py_ssize_t; +typedef unsigned short wchar_t; +typedef struct {} PyObject; +typedef struct {} grammar; +typedef int sdigit; +typedef struct {} DIR; +typedef struct {} RFILE; + + +/* Python/pythonrun.c + * resourece leak false positive */ + +void Py_FatalError(const char *msg) { + __coverity_panic__(); +} + +/* Objects/longobject.c + * NEGATIVE_RETURNS false positive */ + +static PyObject small_ints[257 + 5]; + +static PyObject *get_small_int(sdigit ival) +{ + PyObject *p; + if (((ival + 5) >= 0) && ((ival + 5) < 257 + 5)) { + return &small_ints[ival + 5]; + } + return p; +} + +/* tainted sinks + * + * Coverity considers argv, environ, read() data etc as tained. + */ + +PyObject *PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename) +{ + __coverity_tainted_data_sink__(filename); + return NULL; +} + +/* Python/fileutils.c */ +wchar_t *_Py_char2wchar(const char* arg, size_t *size) +{ + wchar_t *w; + __coverity_tainted_data_sink__(arg); + __coverity_tainted_data_sink__(size); + return w; +} + +/* Parser/pgenmain.c */ +grammar *getgrammar(char *filename) +{ + grammar *g; + __coverity_tainted_data_sink__(filename); + return g; +} + +/* Python/marshal.c */ + +static Py_ssize_t r_string(char *s, Py_ssize_t n, RFILE *p) +{ + __coverity_tainted_string_argument__(s); + return 0; +} + +static long r_long(RFILE *p) +{ + long l; + unsigned char buffer[4]; + + r_string((char *)buffer, 4, p); + __coverity_tainted_string_sanitize_content__(buffer); + l = (long)buffer; + return l; +} + +/* Coverity doesn't understand that fdopendir() may take ownership of fd. */ + +DIR *fdopendir(int fd) { + DIR *d; + if (d) { + __coverity_close__(fd); + } + return d; +} + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 23 02:01:40 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 23 Jul 2013 02:01:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_duplicate_entry_for?= =?utf-8?q?_sdigit=2E?= Message-ID: <3bzfxJ546Qz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/b5d63d699647 changeset: 84802:b5d63d699647 user: Christian Heimes date: Tue Jul 23 02:01:33 2013 +0200 summary: Remove duplicate entry for sdigit. I fixed it before the checkin but forgot to save... :wq files: Misc/coverity_model.c | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Misc/coverity_model.c b/Misc/coverity_model.c --- a/Misc/coverity_model.c +++ b/Misc/coverity_model.c @@ -14,24 +14,19 @@ * Coverity Scan doesn't pick up modifications automatically. The model file * must be uploaded by an admin in the analysis settings of * http://scan.coverity.com/projects/200 - * */ - /* dummy definitions, in most cases struct fields aren't required. */ #define NULL (void *)0 - typedef int sdigit; typedef long Py_ssize_t; typedef unsigned short wchar_t; typedef struct {} PyObject; typedef struct {} grammar; -typedef int sdigit; typedef struct {} DIR; typedef struct {} RFILE; - /* Python/pythonrun.c * resourece leak false positive */ -- Repository URL: http://hg.python.org/cpython From benjamin at python.org Tue Jul 23 02:01:46 2013 From: benjamin at python.org (Benjamin Peterson) Date: Mon, 22 Jul 2013 17:01:46 -0700 Subject: [Python-checkins] [Python-Dev] cpython: Issue #18520: Add a new PyStructSequence_InitType2() function, same than In-Reply-To: References: <3bzcCt6wttz7Ljj@mail.python.org> Message-ID: We've cheerfully broken the ABI before on minor releases, though if it's part of the stable ABI, we can't be cavaliar about that anymore. 2013/7/22 Victor Stinner : > "Add a new PyStructSequence_InitType2()" > > I added a new function because I guess that it would break the API (and ABI) > to change the return type of a function in a minor release. > > Tell me if you have a better name than PyStructSequence_InitType2() ;-) > > "Ex" suffix is usually used when parameters are added. It is not the case > here. > > Victor > > Le 22 juil. 2013 23:59, "victor.stinner" a > ?crit : >> >> http://hg.python.org/cpython/rev/fc718c177ee6 >> changeset: 84793:fc718c177ee6 >> user: Victor Stinner >> date: Mon Jul 22 22:24:54 2013 +0200 >> summary: >> Issue #18520: Add a new PyStructSequence_InitType2() function, same than >> PyStructSequence_InitType() except that it has a return value (0 on >> success, >> -1 on error). >> >> * PyStructSequence_InitType2() now raises MemoryError on memory >> allocation failure >> * Fix also some calls to PyDict_SetItemString(): handle error >> >> files: >> Include/pythonrun.h | 2 +- >> Include/structseq.h | 2 + >> Misc/NEWS | 4 +++ >> Modules/_lsprof.c | 10 ++++--- >> Modules/grpmodule.c | 11 ++++++-- >> Modules/posixmodule.c | 24 ++++++++++++------ >> Modules/pwdmodule.c | 5 ++- >> Modules/resource.c | 9 ++++-- >> Modules/signalmodule.c | 7 +++-- >> Modules/spwdmodule.c | 8 ++++-- >> Modules/timemodule.c | 5 ++- >> Objects/floatobject.c | 9 ++++-- >> Objects/longobject.c | 6 +++- >> Objects/structseq.c | 37 +++++++++++++++++++++-------- >> Python/pythonrun.c | 3 +- >> Python/sysmodule.c | 23 ++++++++++++----- >> Python/thread.c | 6 +++- >> 17 files changed, 117 insertions(+), 54 deletions(-) >> >> >> diff --git a/Include/pythonrun.h b/Include/pythonrun.h >> --- a/Include/pythonrun.h >> +++ b/Include/pythonrun.h >> @@ -197,7 +197,7 @@ >> PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod); >> PyAPI_FUNC(void) _PyImportHooks_Init(void); >> PyAPI_FUNC(int) _PyFrame_Init(void); >> -PyAPI_FUNC(void) _PyFloat_Init(void); >> +PyAPI_FUNC(int) _PyFloat_Init(void); >> PyAPI_FUNC(int) PyByteArray_Init(void); >> PyAPI_FUNC(void) _PyRandom_Init(void); >> #endif >> diff --git a/Include/structseq.h b/Include/structseq.h >> --- a/Include/structseq.h >> +++ b/Include/structseq.h >> @@ -24,6 +24,8 @@ >> #ifndef Py_LIMITED_API >> PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, >> PyStructSequence_Desc *desc); >> +PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type, >> + PyStructSequence_Desc *desc); >> #endif >> PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc >> *desc); >> >> diff --git a/Misc/NEWS b/Misc/NEWS >> --- a/Misc/NEWS >> +++ b/Misc/NEWS >> @@ -10,6 +10,10 @@ >> Core and Builtins >> ----------------- >> >> +- Issue #18520: Add a new PyStructSequence_InitType2() function, same >> than >> + PyStructSequence_InitType() except that it has a return value (0 on >> success, >> + -1 on error). >> + >> - Issue #15905: Fix theoretical buffer overflow in handling of >> sys.argv[0], >> prefix and exec_prefix if the operation system does not obey >> MAXPATHLEN. >> >> diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c >> --- a/Modules/_lsprof.c >> +++ b/Modules/_lsprof.c >> @@ -884,10 +884,12 @@ >> PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type); >> >> if (!initialized) { >> - PyStructSequence_InitType(&StatsEntryType, >> - &profiler_entry_desc); >> - PyStructSequence_InitType(&StatsSubEntryType, >> - &profiler_subentry_desc); >> + if (PyStructSequence_InitType2(&StatsEntryType, >> + &profiler_entry_desc) < 0) >> + return NULL; >> + if (PyStructSequence_InitType2(&StatsSubEntryType, >> + &profiler_subentry_desc) < 0) >> + return NULL; >> } >> Py_INCREF((PyObject*) &StatsEntryType); >> Py_INCREF((PyObject*) &StatsSubEntryType); >> diff --git a/Modules/grpmodule.c b/Modules/grpmodule.c >> --- a/Modules/grpmodule.c >> +++ b/Modules/grpmodule.c >> @@ -210,9 +210,14 @@ >> if (m == NULL) >> return NULL; >> d = PyModule_GetDict(m); >> - if (!initialized) >> - PyStructSequence_InitType(&StructGrpType, >> &struct_group_type_desc); >> - PyDict_SetItemString(d, "struct_group", (PyObject *) &StructGrpType); >> + if (!initialized) { >> + if (PyStructSequence_InitType2(&StructGrpType, >> + &struct_group_type_desc) < 0) >> + return NULL; >> + } >> + if (PyDict_SetItemString(d, "struct_group", >> + (PyObject *)&StructGrpType) < 0) >> + return NULL; >> initialized = 1; >> return m; >> } >> diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c >> --- a/Modules/posixmodule.c >> +++ b/Modules/posixmodule.c >> @@ -11518,19 +11518,23 @@ >> if (!initialized) { >> #if defined(HAVE_WAITID) && !defined(__APPLE__) >> waitid_result_desc.name = MODNAME ".waitid_result"; >> - PyStructSequence_InitType(&WaitidResultType, >> &waitid_result_desc); >> + if (PyStructSequence_InitType2(&WaitidResultType, >> &waitid_result_desc) < 0) >> + return NULL; >> #endif >> >> stat_result_desc.name = MODNAME ".stat_result"; >> stat_result_desc.fields[7].name = PyStructSequence_UnnamedField; >> stat_result_desc.fields[8].name = PyStructSequence_UnnamedField; >> stat_result_desc.fields[9].name = PyStructSequence_UnnamedField; >> - PyStructSequence_InitType(&StatResultType, &stat_result_desc); >> + if (PyStructSequence_InitType2(&StatResultType, >> &stat_result_desc) < 0) >> + return NULL; >> structseq_new = StatResultType.tp_new; >> StatResultType.tp_new = statresult_new; >> >> statvfs_result_desc.name = MODNAME ".statvfs_result"; >> - PyStructSequence_InitType(&StatVFSResultType, >> &statvfs_result_desc); >> + if (PyStructSequence_InitType2(&StatVFSResultType, >> + &statvfs_result_desc) < 0) >> + return NULL; >> #ifdef NEED_TICKS_PER_SECOND >> # if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) >> ticks_per_second = sysconf(_SC_CLK_TCK); >> @@ -11543,12 +11547,15 @@ >> >> #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) >> sched_param_desc.name = MODNAME ".sched_param"; >> - PyStructSequence_InitType(&SchedParamType, &sched_param_desc); >> + if (PyStructSequence_InitType2(&SchedParamType, >> &sched_param_desc) < 0) >> + return NULL; >> SchedParamType.tp_new = sched_param_new; >> #endif >> >> /* initialize TerminalSize_info */ >> - PyStructSequence_InitType(&TerminalSizeType, &TerminalSize_desc); >> + if (PyStructSequence_InitType2(&TerminalSizeType, >> + &TerminalSize_desc) < 0) >> + return NULL; >> } >> #if defined(HAVE_WAITID) && !defined(__APPLE__) >> Py_INCREF((PyObject*) &WaitidResultType); >> @@ -11566,11 +11573,13 @@ >> #endif >> >> times_result_desc.name = MODNAME ".times_result"; >> - PyStructSequence_InitType(&TimesResultType, ×_result_desc); >> + if (PyStructSequence_InitType2(&TimesResultType, ×_result_desc) >> < 0) >> + return NULL; >> PyModule_AddObject(m, "times_result", (PyObject *)&TimesResultType); >> >> uname_result_desc.name = MODNAME ".uname_result"; >> - PyStructSequence_InitType(&UnameResultType, &uname_result_desc); >> + if (PyStructSequence_InitType2(&UnameResultType, &uname_result_desc) >> < 0) >> + return NULL; >> PyModule_AddObject(m, "uname_result", (PyObject *)&UnameResultType); >> >> #ifdef __APPLE__ >> @@ -11648,7 +11657,6 @@ >> initialized = 1; >> >> return m; >> - >> } >> >> #ifdef __cplusplus >> diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c >> --- a/Modules/pwdmodule.c >> +++ b/Modules/pwdmodule.c >> @@ -216,8 +216,9 @@ >> return NULL; >> >> if (!initialized) { >> - PyStructSequence_InitType(&StructPwdType, >> - &struct_pwd_type_desc); >> + if (PyStructSequence_InitType2(&StructPwdType, >> + &struct_pwd_type_desc) < 0) >> + return NULL; >> initialized = 1; >> } >> Py_INCREF((PyObject *) &StructPwdType); >> diff --git a/Modules/resource.c b/Modules/resource.c >> --- a/Modules/resource.c >> +++ b/Modules/resource.c >> @@ -263,9 +263,12 @@ >> /* Add some symbolic constants to the module */ >> Py_INCREF(PyExc_OSError); >> PyModule_AddObject(m, "error", PyExc_OSError); >> - if (!initialized) >> - PyStructSequence_InitType(&StructRUsageType, >> - &struct_rusage_desc); >> + if (!initialized) { >> + if (PyStructSequence_InitType2(&StructRUsageType, >> + &struct_rusage_desc) < 0) >> + return NULL; >> + } >> + >> Py_INCREF(&StructRUsageType); >> PyModule_AddObject(m, "struct_rusage", >> (PyObject*) &StructRUsageType); >> diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c >> --- a/Modules/signalmodule.c >> +++ b/Modules/signalmodule.c >> @@ -978,9 +978,10 @@ >> return NULL; >> >> #if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT) >> - if (!initialized) >> - PyStructSequence_InitType(&SiginfoType, &struct_siginfo_desc); >> - >> + if (!initialized) { >> + if (PyStructSequence_InitType2(&SiginfoType, >> &struct_siginfo_desc) < 0) >> + return NULL; >> + } >> Py_INCREF((PyObject*) &SiginfoType); >> PyModule_AddObject(m, "struct_siginfo", (PyObject*) &SiginfoType); >> initialized = 1; >> diff --git a/Modules/spwdmodule.c b/Modules/spwdmodule.c >> --- a/Modules/spwdmodule.c >> +++ b/Modules/spwdmodule.c >> @@ -196,9 +196,11 @@ >> m=PyModule_Create(&spwdmodule); >> if (m == NULL) >> return NULL; >> - if (!initialized) >> - PyStructSequence_InitType(&StructSpwdType, >> - &struct_spwd_type_desc); >> + if (!initialized) { >> + if (PyStructSequence_InitType2(&StructSpwdType, >> + &struct_spwd_type_desc) < 0) >> + return NULL; >> + } >> Py_INCREF((PyObject *) &StructSpwdType); >> PyModule_AddObject(m, "struct_spwd", (PyObject *) &StructSpwdType); >> initialized = 1; >> diff --git a/Modules/timemodule.c b/Modules/timemodule.c >> --- a/Modules/timemodule.c >> +++ b/Modules/timemodule.c >> @@ -1476,8 +1476,9 @@ >> PyInit_timezone(m); >> >> if (!initialized) { >> - PyStructSequence_InitType(&StructTimeType, >> - &struct_time_type_desc); >> + if (PyStructSequence_InitType2(&StructTimeType, >> + &struct_time_type_desc) < 0) >> + return NULL; >> >> #ifdef MS_WINDOWS >> winver.dwOSVersionInfoSize = sizeof(winver); >> diff --git a/Objects/floatobject.c b/Objects/floatobject.c >> --- a/Objects/floatobject.c >> +++ b/Objects/floatobject.c >> @@ -1853,7 +1853,7 @@ >> float_new, /* tp_new */ >> }; >> >> -void >> +int >> _PyFloat_Init(void) >> { >> /* We attempt to determine if this machine is using IEEE >> @@ -1903,8 +1903,11 @@ >> float_format = detected_float_format; >> >> /* Init float info */ >> - if (FloatInfoType.tp_name == 0) >> - PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc); >> + if (FloatInfoType.tp_name == NULL) { >> + if (PyStructSequence_InitType2(&FloatInfoType, &floatinfo_desc) < >> 0) >> + return 0; >> + } >> + return 1; >> } >> >> int >> diff --git a/Objects/longobject.c b/Objects/longobject.c >> --- a/Objects/longobject.c >> +++ b/Objects/longobject.c >> @@ -5059,8 +5059,10 @@ >> } >> #endif >> /* initialize int_info */ >> - if (Int_InfoType.tp_name == 0) >> - PyStructSequence_InitType(&Int_InfoType, &int_info_desc); >> + if (Int_InfoType.tp_name == NULL) { >> + if (PyStructSequence_InitType2(&Int_InfoType, &int_info_desc) < >> 0) >> + return 0; >> + } >> >> return 1; >> } >> diff --git a/Objects/structseq.c b/Objects/structseq.c >> --- a/Objects/structseq.c >> +++ b/Objects/structseq.c >> @@ -320,12 +320,13 @@ >> structseq_new, /* tp_new */ >> }; >> >> -void >> -PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc >> *desc) >> +int >> +PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc >> *desc) >> { >> PyObject *dict; >> PyMemberDef* members; >> int n_members, n_unnamed_members, i, k; >> + PyObject *v; >> >> #ifdef Py_TRACE_REFS >> /* if the type object was chained, unchain it first >> @@ -347,8 +348,10 @@ >> type->tp_doc = desc->doc; >> >> members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1); >> - if (members == NULL) >> - return; >> + if (members == NULL) { >> + PyErr_NoMemory(); >> + return -1; >> + } >> >> for (i = k = 0; i < n_members; ++i) { >> if (desc->fields[i].name == PyStructSequence_UnnamedField) >> @@ -366,22 +369,33 @@ >> type->tp_members = members; >> >> if (PyType_Ready(type) < 0) >> - return; >> + return -1; >> Py_INCREF(type); >> >> dict = type->tp_dict; >> #define SET_DICT_FROM_INT(key, value) \ >> do { \ >> - PyObject *v = PyLong_FromLong((long) value); \ >> - if (v != NULL) { \ >> - PyDict_SetItemString(dict, key, v); \ >> + v = PyLong_FromLong((long) value); \ >> + if (v == NULL) \ >> + return -1; \ >> + if (PyDict_SetItemString(dict, key, v) < 0) { \ >> Py_DECREF(v); \ >> + return -1; \ >> } \ >> + Py_DECREF(v); \ >> } while (0) >> >> SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence); >> SET_DICT_FROM_INT(real_length_key, n_members); >> SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members); >> + >> + return 0; >> +} >> + >> +void >> +PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc >> *desc) >> +{ >> + (void)PyStructSequence_InitType2(type, desc); >> } >> >> PyTypeObject* >> @@ -390,8 +404,11 @@ >> PyTypeObject *result; >> >> result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); >> - if (result != NULL) { >> - PyStructSequence_InitType(result, desc); >> + if (result == NULL) >> + return NULL; >> + if (PyStructSequence_InitType2(result, desc) < 0) { >> + Py_DECREF(result); >> + return NULL; >> } >> return result; >> } >> diff --git a/Python/pythonrun.c b/Python/pythonrun.c >> --- a/Python/pythonrun.c >> +++ b/Python/pythonrun.c >> @@ -328,7 +328,8 @@ >> if (!PyByteArray_Init()) >> Py_FatalError("Py_Initialize: can't init bytearray"); >> >> - _PyFloat_Init(); >> + if (!_PyFloat_Init()) >> + Py_FatalError("Py_Initialize: can't init float"); >> >> interp->modules = PyDict_New(); >> if (interp->modules == NULL) >> diff --git a/Python/sysmodule.c b/Python/sysmodule.c >> --- a/Python/sysmodule.c >> +++ b/Python/sysmodule.c >> @@ -1634,8 +1634,10 @@ >> SET_SYS_FROM_STRING("int_info", >> PyLong_GetInfo()); >> /* initialize hash_info */ >> - if (Hash_InfoType.tp_name == 0) >> - PyStructSequence_InitType(&Hash_InfoType, &hash_info_desc); >> + if (Hash_InfoType.tp_name == NULL) { >> + if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < >> 0) >> + return NULL; >> + } >> SET_SYS_FROM_STRING("hash_info", >> get_hash_info()); >> SET_SYS_FROM_STRING("maxunicode", >> @@ -1676,8 +1678,11 @@ >> } >> >> /* version_info */ >> - if (VersionInfoType.tp_name == 0) >> - PyStructSequence_InitType(&VersionInfoType, &version_info_desc); >> + if (VersionInfoType.tp_name == NULL) { >> + if (PyStructSequence_InitType2(&VersionInfoType, >> + &version_info_desc) < 0) >> + return NULL; >> + } >> version_info = make_version_info(); >> SET_SYS_FROM_STRING("version_info", version_info); >> /* prevent user from creating new instances */ >> @@ -1688,8 +1693,10 @@ >> SET_SYS_FROM_STRING("implementation", make_impl_info(version_info)); >> >> /* flags */ >> - if (FlagsType.tp_name == 0) >> - PyStructSequence_InitType(&FlagsType, &flags_desc); >> + if (FlagsType.tp_name == 0) { >> + if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0) >> + return NULL; >> + } >> SET_SYS_FROM_STRING("flags", make_flags()); >> /* prevent user from creating new instances */ >> FlagsType.tp_init = NULL; >> @@ -1699,7 +1706,9 @@ >> #if defined(MS_WINDOWS) >> /* getwindowsversion */ >> if (WindowsVersionType.tp_name == 0) >> - PyStructSequence_InitType(&WindowsVersionType, >> &windows_version_desc); >> + if (PyStructSequence_InitType2(&WindowsVersionType, >> + &windows_version_desc) < 0) >> + return NULL; >> /* prevent user from creating new instances */ >> WindowsVersionType.tp_init = NULL; >> WindowsVersionType.tp_new = NULL; >> diff --git a/Python/thread.c b/Python/thread.c >> --- a/Python/thread.c >> +++ b/Python/thread.c >> @@ -399,8 +399,10 @@ >> int len; >> #endif >> >> - if (ThreadInfoType.tp_name == 0) >> - PyStructSequence_InitType(&ThreadInfoType, &threadinfo_desc); >> + if (ThreadInfoType.tp_name == 0) { >> + if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) >> < 0) >> + return NULL; >> + } >> >> threadinfo = PyStructSequence_New(&ThreadInfoType); >> if (threadinfo == 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 >> > > _______________________________________________ > Python-Dev mailing list > Python-Dev at python.org > http://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > http://mail.python.org/mailman/options/python-dev/benjamin%40python.org > -- Regards, Benjamin From python-checkins at python.org Tue Jul 23 02:05:55 2013 From: python-checkins at python.org (brian.curtin) Date: Tue, 23 Jul 2013 02:05:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_in_a_comment_that_was_?= =?utf-8?q?removed_in_240adc564539_=28requested_by_Victor_Stinner=29?= Message-ID: <3bzg2C52Y3zPYy@mail.python.org> http://hg.python.org/cpython/rev/d6213012d87b changeset: 84803:d6213012d87b user: Brian Curtin date: Mon Jul 22 19:05:48 2013 -0500 summary: Add in a comment that was removed in 240adc564539 (requested by Victor Stinner) files: Lib/posixpath.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -188,6 +188,7 @@ # It doesn't exist -- so not a mount point. :-) return False else: + # A symlink can never be a mount point if stat.S_ISLNK(s1.st_mode): return False -- Repository URL: http://hg.python.org/cpython From brian at python.org Tue Jul 23 02:06:59 2013 From: brian at python.org (Brian Curtin) Date: Mon, 22 Jul 2013 19:06:59 -0500 Subject: [Python-checkins] [Python-Dev] cpython: Fix #18530. Remove extra stat call from posixpath.ismount In-Reply-To: References: <3bzW5x3YpTz7Lks@mail.python.org> Message-ID: On Mon, Jul 22, 2013 at 6:36 PM, Victor Stinner wrote: > Could you please keep the comment "# A symlink can never be a mount point" ? > It is useful. (I didn't know that, I'm not a windows developer.) I don't think that's specific to Windows, but I added it back in d6213012d87b. From solipsis at pitrou.net Tue Jul 23 05:56:38 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 23 Jul 2013 05:56:38 +0200 Subject: [Python-checkins] Daily reference leaks (d6213012d87b): sum=0 Message-ID: results for d6213012d87b on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogno56vA', '-x'] From python-checkins at python.org Tue Jul 23 07:08:39 2013 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 23 Jul 2013 07:08:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_return_NULL_he?= =?utf-8?q?re?= Message-ID: <3bznlW6d69z7LkD@mail.python.org> http://hg.python.org/cpython/rev/042ff9325c5e changeset: 84804:042ff9325c5e branch: 3.3 parent: 84789:bb63f813a00f user: Benjamin Peterson date: Mon Jul 22 22:08:09 2013 -0700 summary: return NULL here files: Python/dynload_shlib.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -91,7 +91,8 @@ int i; struct stat statb; if (fstat(fileno(fp), &statb) == -1) { - return PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_IOError); + return NULL; } for (i = 0; i < nhandles; i++) { if (statb.st_dev == handles[i].dev && -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 23 07:08:41 2013 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 23 Jul 2013 07:08:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3bznlY1QSQz7Llw@mail.python.org> http://hg.python.org/cpython/rev/a5681f50bae2 changeset: 84805:a5681f50bae2 parent: 84803:d6213012d87b parent: 84804:042ff9325c5e user: Benjamin Peterson date: Mon Jul 22 22:08:17 2013 -0700 summary: merge 3.3 files: Python/dynload_shlib.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -82,7 +82,8 @@ int i; struct stat statb; if (fstat(fileno(fp), &statb) == -1) { - return PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_IOError); + return NULL; } for (i = 0; i < nhandles; i++) { if (statb.st_dev == handles[i].dev && -- Repository URL: http://hg.python.org/cpython From ronaldoussoren at mac.com Tue Jul 23 08:15:29 2013 From: ronaldoussoren at mac.com (Ronald Oussoren) Date: Tue, 23 Jul 2013 08:15:29 +0200 Subject: [Python-checkins] [Python-Dev] cpython: Issue #18520: Add a new PyStructSequence_InitType2() function, same than In-Reply-To: References: <3bzcCt6wttz7Ljj@mail.python.org> Message-ID: On 23 Jul, 2013, at 2:01, Benjamin Peterson wrote: > We've cheerfully broken the ABI before on minor releases, though if > it's part of the stable ABI, we can't be cavaliar about that anymore. It is not part of the stable ABI. Given that the implementation of PyStructSequence_InitType() in the patch just calls PyStructSequence_InitType2() and ignores the return value you could change the return value of ..InitType(). This may or may not break existing extensions using the function (depending on platform ABI details, AFAIK this is not a problem on x86/x86_64), but reusing extensions across python feature releases is not supported anyway. There are no problems when compiling code, most C compilers won't even warn about ignored return values unless you explicitly ask for it. Ronald > > 2013/7/22 Victor Stinner : >> "Add a new PyStructSequence_InitType2()" >> >> I added a new function because I guess that it would break the API (and ABI) >> to change the return type of a function in a minor release. >> >> Tell me if you have a better name than PyStructSequence_InitType2() ;-) >> >> "Ex" suffix is usually used when parameters are added. It is not the case >> here. >> >> Victor >> >> Le 22 juil. 2013 23:59, "victor.stinner" a >> ?crit : >>> >>> http://hg.python.org/cpython/rev/fc718c177ee6 >>> changeset: 84793:fc718c177ee6 >>> user: Victor Stinner >>> date: Mon Jul 22 22:24:54 2013 +0200 >>> summary: >>> Issue #18520: Add a new PyStructSequence_InitType2() function, same than >>> PyStructSequence_InitType() except that it has a return value (0 on >>> success, >>> -1 on error). >>> >>> * PyStructSequence_InitType2() now raises MemoryError on memory >>> allocation failure >>> * Fix also some calls to PyDict_SetItemString(): handle error >>> >>> files: >>> Include/pythonrun.h | 2 +- >>> Include/structseq.h | 2 + >>> Misc/NEWS | 4 +++ >>> Modules/_lsprof.c | 10 ++++--- >>> Modules/grpmodule.c | 11 ++++++-- >>> Modules/posixmodule.c | 24 ++++++++++++------ >>> Modules/pwdmodule.c | 5 ++- >>> Modules/resource.c | 9 ++++-- >>> Modules/signalmodule.c | 7 +++-- >>> Modules/spwdmodule.c | 8 ++++-- >>> Modules/timemodule.c | 5 ++- >>> Objects/floatobject.c | 9 ++++-- >>> Objects/longobject.c | 6 +++- >>> Objects/structseq.c | 37 +++++++++++++++++++++-------- >>> Python/pythonrun.c | 3 +- >>> Python/sysmodule.c | 23 ++++++++++++----- >>> Python/thread.c | 6 +++- >>> 17 files changed, 117 insertions(+), 54 deletions(-) >>> >>> >>> diff --git a/Include/pythonrun.h b/Include/pythonrun.h >>> --- a/Include/pythonrun.h >>> +++ b/Include/pythonrun.h >>> @@ -197,7 +197,7 @@ >>> PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod); >>> PyAPI_FUNC(void) _PyImportHooks_Init(void); >>> PyAPI_FUNC(int) _PyFrame_Init(void); >>> -PyAPI_FUNC(void) _PyFloat_Init(void); >>> +PyAPI_FUNC(int) _PyFloat_Init(void); >>> PyAPI_FUNC(int) PyByteArray_Init(void); >>> PyAPI_FUNC(void) _PyRandom_Init(void); >>> #endif >>> diff --git a/Include/structseq.h b/Include/structseq.h >>> --- a/Include/structseq.h >>> +++ b/Include/structseq.h >>> @@ -24,6 +24,8 @@ >>> #ifndef Py_LIMITED_API >>> PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, >>> PyStructSequence_Desc *desc); >>> +PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type, >>> + PyStructSequence_Desc *desc); >>> #endif >>> PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc >>> *desc); >>> >>> diff --git a/Misc/NEWS b/Misc/NEWS >>> --- a/Misc/NEWS >>> +++ b/Misc/NEWS >>> @@ -10,6 +10,10 @@ >>> Core and Builtins >>> ----------------- >>> >>> +- Issue #18520: Add a new PyStructSequence_InitType2() function, same >>> than >>> + PyStructSequence_InitType() except that it has a return value (0 on >>> success, >>> + -1 on error). >>> + >>> - Issue #15905: Fix theoretical buffer overflow in handling of >>> sys.argv[0], >>> prefix and exec_prefix if the operation system does not obey >>> MAXPATHLEN. >>> >>> diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c >>> --- a/Modules/_lsprof.c >>> +++ b/Modules/_lsprof.c >>> @@ -884,10 +884,12 @@ >>> PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type); >>> >>> if (!initialized) { >>> - PyStructSequence_InitType(&StatsEntryType, >>> - &profiler_entry_desc); >>> - PyStructSequence_InitType(&StatsSubEntryType, >>> - &profiler_subentry_desc); >>> + if (PyStructSequence_InitType2(&StatsEntryType, >>> + &profiler_entry_desc) < 0) >>> + return NULL; >>> + if (PyStructSequence_InitType2(&StatsSubEntryType, >>> + &profiler_subentry_desc) < 0) >>> + return NULL; >>> } >>> Py_INCREF((PyObject*) &StatsEntryType); >>> Py_INCREF((PyObject*) &StatsSubEntryType); >>> diff --git a/Modules/grpmodule.c b/Modules/grpmodule.c >>> --- a/Modules/grpmodule.c >>> +++ b/Modules/grpmodule.c >>> @@ -210,9 +210,14 @@ >>> if (m == NULL) >>> return NULL; >>> d = PyModule_GetDict(m); >>> - if (!initialized) >>> - PyStructSequence_InitType(&StructGrpType, >>> &struct_group_type_desc); >>> - PyDict_SetItemString(d, "struct_group", (PyObject *) &StructGrpType); >>> + if (!initialized) { >>> + if (PyStructSequence_InitType2(&StructGrpType, >>> + &struct_group_type_desc) < 0) >>> + return NULL; >>> + } >>> + if (PyDict_SetItemString(d, "struct_group", >>> + (PyObject *)&StructGrpType) < 0) >>> + return NULL; >>> initialized = 1; >>> return m; >>> } >>> diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c >>> --- a/Modules/posixmodule.c >>> +++ b/Modules/posixmodule.c >>> @@ -11518,19 +11518,23 @@ >>> if (!initialized) { >>> #if defined(HAVE_WAITID) && !defined(__APPLE__) >>> waitid_result_desc.name = MODNAME ".waitid_result"; >>> - PyStructSequence_InitType(&WaitidResultType, >>> &waitid_result_desc); >>> + if (PyStructSequence_InitType2(&WaitidResultType, >>> &waitid_result_desc) < 0) >>> + return NULL; >>> #endif >>> >>> stat_result_desc.name = MODNAME ".stat_result"; >>> stat_result_desc.fields[7].name = PyStructSequence_UnnamedField; >>> stat_result_desc.fields[8].name = PyStructSequence_UnnamedField; >>> stat_result_desc.fields[9].name = PyStructSequence_UnnamedField; >>> - PyStructSequence_InitType(&StatResultType, &stat_result_desc); >>> + if (PyStructSequence_InitType2(&StatResultType, >>> &stat_result_desc) < 0) >>> + return NULL; >>> structseq_new = StatResultType.tp_new; >>> StatResultType.tp_new = statresult_new; >>> >>> statvfs_result_desc.name = MODNAME ".statvfs_result"; >>> - PyStructSequence_InitType(&StatVFSResultType, >>> &statvfs_result_desc); >>> + if (PyStructSequence_InitType2(&StatVFSResultType, >>> + &statvfs_result_desc) < 0) >>> + return NULL; >>> #ifdef NEED_TICKS_PER_SECOND >>> # if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) >>> ticks_per_second = sysconf(_SC_CLK_TCK); >>> @@ -11543,12 +11547,15 @@ >>> >>> #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) >>> sched_param_desc.name = MODNAME ".sched_param"; >>> - PyStructSequence_InitType(&SchedParamType, &sched_param_desc); >>> + if (PyStructSequence_InitType2(&SchedParamType, >>> &sched_param_desc) < 0) >>> + return NULL; >>> SchedParamType.tp_new = sched_param_new; >>> #endif >>> >>> /* initialize TerminalSize_info */ >>> - PyStructSequence_InitType(&TerminalSizeType, &TerminalSize_desc); >>> + if (PyStructSequence_InitType2(&TerminalSizeType, >>> + &TerminalSize_desc) < 0) >>> + return NULL; >>> } >>> #if defined(HAVE_WAITID) && !defined(__APPLE__) >>> Py_INCREF((PyObject*) &WaitidResultType); >>> @@ -11566,11 +11573,13 @@ >>> #endif >>> >>> times_result_desc.name = MODNAME ".times_result"; >>> - PyStructSequence_InitType(&TimesResultType, ×_result_desc); >>> + if (PyStructSequence_InitType2(&TimesResultType, ×_result_desc) >>> < 0) >>> + return NULL; >>> PyModule_AddObject(m, "times_result", (PyObject *)&TimesResultType); >>> >>> uname_result_desc.name = MODNAME ".uname_result"; >>> - PyStructSequence_InitType(&UnameResultType, &uname_result_desc); >>> + if (PyStructSequence_InitType2(&UnameResultType, &uname_result_desc) >>> < 0) >>> + return NULL; >>> PyModule_AddObject(m, "uname_result", (PyObject *)&UnameResultType); >>> >>> #ifdef __APPLE__ >>> @@ -11648,7 +11657,6 @@ >>> initialized = 1; >>> >>> return m; >>> - >>> } >>> >>> #ifdef __cplusplus >>> diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c >>> --- a/Modules/pwdmodule.c >>> +++ b/Modules/pwdmodule.c >>> @@ -216,8 +216,9 @@ >>> return NULL; >>> >>> if (!initialized) { >>> - PyStructSequence_InitType(&StructPwdType, >>> - &struct_pwd_type_desc); >>> + if (PyStructSequence_InitType2(&StructPwdType, >>> + &struct_pwd_type_desc) < 0) >>> + return NULL; >>> initialized = 1; >>> } >>> Py_INCREF((PyObject *) &StructPwdType); >>> diff --git a/Modules/resource.c b/Modules/resource.c >>> --- a/Modules/resource.c >>> +++ b/Modules/resource.c >>> @@ -263,9 +263,12 @@ >>> /* Add some symbolic constants to the module */ >>> Py_INCREF(PyExc_OSError); >>> PyModule_AddObject(m, "error", PyExc_OSError); >>> - if (!initialized) >>> - PyStructSequence_InitType(&StructRUsageType, >>> - &struct_rusage_desc); >>> + if (!initialized) { >>> + if (PyStructSequence_InitType2(&StructRUsageType, >>> + &struct_rusage_desc) < 0) >>> + return NULL; >>> + } >>> + >>> Py_INCREF(&StructRUsageType); >>> PyModule_AddObject(m, "struct_rusage", >>> (PyObject*) &StructRUsageType); >>> diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c >>> --- a/Modules/signalmodule.c >>> +++ b/Modules/signalmodule.c >>> @@ -978,9 +978,10 @@ >>> return NULL; >>> >>> #if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT) >>> - if (!initialized) >>> - PyStructSequence_InitType(&SiginfoType, &struct_siginfo_desc); >>> - >>> + if (!initialized) { >>> + if (PyStructSequence_InitType2(&SiginfoType, >>> &struct_siginfo_desc) < 0) >>> + return NULL; >>> + } >>> Py_INCREF((PyObject*) &SiginfoType); >>> PyModule_AddObject(m, "struct_siginfo", (PyObject*) &SiginfoType); >>> initialized = 1; >>> diff --git a/Modules/spwdmodule.c b/Modules/spwdmodule.c >>> --- a/Modules/spwdmodule.c >>> +++ b/Modules/spwdmodule.c >>> @@ -196,9 +196,11 @@ >>> m=PyModule_Create(&spwdmodule); >>> if (m == NULL) >>> return NULL; >>> - if (!initialized) >>> - PyStructSequence_InitType(&StructSpwdType, >>> - &struct_spwd_type_desc); >>> + if (!initialized) { >>> + if (PyStructSequence_InitType2(&StructSpwdType, >>> + &struct_spwd_type_desc) < 0) >>> + return NULL; >>> + } >>> Py_INCREF((PyObject *) &StructSpwdType); >>> PyModule_AddObject(m, "struct_spwd", (PyObject *) &StructSpwdType); >>> initialized = 1; >>> diff --git a/Modules/timemodule.c b/Modules/timemodule.c >>> --- a/Modules/timemodule.c >>> +++ b/Modules/timemodule.c >>> @@ -1476,8 +1476,9 @@ >>> PyInit_timezone(m); >>> >>> if (!initialized) { >>> - PyStructSequence_InitType(&StructTimeType, >>> - &struct_time_type_desc); >>> + if (PyStructSequence_InitType2(&StructTimeType, >>> + &struct_time_type_desc) < 0) >>> + return NULL; >>> >>> #ifdef MS_WINDOWS >>> winver.dwOSVersionInfoSize = sizeof(winver); >>> diff --git a/Objects/floatobject.c b/Objects/floatobject.c >>> --- a/Objects/floatobject.c >>> +++ b/Objects/floatobject.c >>> @@ -1853,7 +1853,7 @@ >>> float_new, /* tp_new */ >>> }; >>> >>> -void >>> +int >>> _PyFloat_Init(void) >>> { >>> /* We attempt to determine if this machine is using IEEE >>> @@ -1903,8 +1903,11 @@ >>> float_format = detected_float_format; >>> >>> /* Init float info */ >>> - if (FloatInfoType.tp_name == 0) >>> - PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc); >>> + if (FloatInfoType.tp_name == NULL) { >>> + if (PyStructSequence_InitType2(&FloatInfoType, &floatinfo_desc) < >>> 0) >>> + return 0; >>> + } >>> + return 1; >>> } >>> >>> int >>> diff --git a/Objects/longobject.c b/Objects/longobject.c >>> --- a/Objects/longobject.c >>> +++ b/Objects/longobject.c >>> @@ -5059,8 +5059,10 @@ >>> } >>> #endif >>> /* initialize int_info */ >>> - if (Int_InfoType.tp_name == 0) >>> - PyStructSequence_InitType(&Int_InfoType, &int_info_desc); >>> + if (Int_InfoType.tp_name == NULL) { >>> + if (PyStructSequence_InitType2(&Int_InfoType, &int_info_desc) < >>> 0) >>> + return 0; >>> + } >>> >>> return 1; >>> } >>> diff --git a/Objects/structseq.c b/Objects/structseq.c >>> --- a/Objects/structseq.c >>> +++ b/Objects/structseq.c >>> @@ -320,12 +320,13 @@ >>> structseq_new, /* tp_new */ >>> }; >>> >>> -void >>> -PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc >>> *desc) >>> +int >>> +PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc >>> *desc) >>> { >>> PyObject *dict; >>> PyMemberDef* members; >>> int n_members, n_unnamed_members, i, k; >>> + PyObject *v; >>> >>> #ifdef Py_TRACE_REFS >>> /* if the type object was chained, unchain it first >>> @@ -347,8 +348,10 @@ >>> type->tp_doc = desc->doc; >>> >>> members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1); >>> - if (members == NULL) >>> - return; >>> + if (members == NULL) { >>> + PyErr_NoMemory(); >>> + return -1; >>> + } >>> >>> for (i = k = 0; i < n_members; ++i) { >>> if (desc->fields[i].name == PyStructSequence_UnnamedField) >>> @@ -366,22 +369,33 @@ >>> type->tp_members = members; >>> >>> if (PyType_Ready(type) < 0) >>> - return; >>> + return -1; >>> Py_INCREF(type); >>> >>> dict = type->tp_dict; >>> #define SET_DICT_FROM_INT(key, value) \ >>> do { \ >>> - PyObject *v = PyLong_FromLong((long) value); \ >>> - if (v != NULL) { \ >>> - PyDict_SetItemString(dict, key, v); \ >>> + v = PyLong_FromLong((long) value); \ >>> + if (v == NULL) \ >>> + return -1; \ >>> + if (PyDict_SetItemString(dict, key, v) < 0) { \ >>> Py_DECREF(v); \ >>> + return -1; \ >>> } \ >>> + Py_DECREF(v); \ >>> } while (0) >>> >>> SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence); >>> SET_DICT_FROM_INT(real_length_key, n_members); >>> SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members); >>> + >>> + return 0; >>> +} >>> + >>> +void >>> +PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc >>> *desc) >>> +{ >>> + (void)PyStructSequence_InitType2(type, desc); >>> } >>> >>> PyTypeObject* >>> @@ -390,8 +404,11 @@ >>> PyTypeObject *result; >>> >>> result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); >>> - if (result != NULL) { >>> - PyStructSequence_InitType(result, desc); >>> + if (result == NULL) >>> + return NULL; >>> + if (PyStructSequence_InitType2(result, desc) < 0) { >>> + Py_DECREF(result); >>> + return NULL; >>> } >>> return result; >>> } >>> diff --git a/Python/pythonrun.c b/Python/pythonrun.c >>> --- a/Python/pythonrun.c >>> +++ b/Python/pythonrun.c >>> @@ -328,7 +328,8 @@ >>> if (!PyByteArray_Init()) >>> Py_FatalError("Py_Initialize: can't init bytearray"); >>> >>> - _PyFloat_Init(); >>> + if (!_PyFloat_Init()) >>> + Py_FatalError("Py_Initialize: can't init float"); >>> >>> interp->modules = PyDict_New(); >>> if (interp->modules == NULL) >>> diff --git a/Python/sysmodule.c b/Python/sysmodule.c >>> --- a/Python/sysmodule.c >>> +++ b/Python/sysmodule.c >>> @@ -1634,8 +1634,10 @@ >>> SET_SYS_FROM_STRING("int_info", >>> PyLong_GetInfo()); >>> /* initialize hash_info */ >>> - if (Hash_InfoType.tp_name == 0) >>> - PyStructSequence_InitType(&Hash_InfoType, &hash_info_desc); >>> + if (Hash_InfoType.tp_name == NULL) { >>> + if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < >>> 0) >>> + return NULL; >>> + } >>> SET_SYS_FROM_STRING("hash_info", >>> get_hash_info()); >>> SET_SYS_FROM_STRING("maxunicode", >>> @@ -1676,8 +1678,11 @@ >>> } >>> >>> /* version_info */ >>> - if (VersionInfoType.tp_name == 0) >>> - PyStructSequence_InitType(&VersionInfoType, &version_info_desc); >>> + if (VersionInfoType.tp_name == NULL) { >>> + if (PyStructSequence_InitType2(&VersionInfoType, >>> + &version_info_desc) < 0) >>> + return NULL; >>> + } >>> version_info = make_version_info(); >>> SET_SYS_FROM_STRING("version_info", version_info); >>> /* prevent user from creating new instances */ >>> @@ -1688,8 +1693,10 @@ >>> SET_SYS_FROM_STRING("implementation", make_impl_info(version_info)); >>> >>> /* flags */ >>> - if (FlagsType.tp_name == 0) >>> - PyStructSequence_InitType(&FlagsType, &flags_desc); >>> + if (FlagsType.tp_name == 0) { >>> + if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0) >>> + return NULL; >>> + } >>> SET_SYS_FROM_STRING("flags", make_flags()); >>> /* prevent user from creating new instances */ >>> FlagsType.tp_init = NULL; >>> @@ -1699,7 +1706,9 @@ >>> #if defined(MS_WINDOWS) >>> /* getwindowsversion */ >>> if (WindowsVersionType.tp_name == 0) >>> - PyStructSequence_InitType(&WindowsVersionType, >>> &windows_version_desc); >>> + if (PyStructSequence_InitType2(&WindowsVersionType, >>> + &windows_version_desc) < 0) >>> + return NULL; >>> /* prevent user from creating new instances */ >>> WindowsVersionType.tp_init = NULL; >>> WindowsVersionType.tp_new = NULL; >>> diff --git a/Python/thread.c b/Python/thread.c >>> --- a/Python/thread.c >>> +++ b/Python/thread.c >>> @@ -399,8 +399,10 @@ >>> int len; >>> #endif >>> >>> - if (ThreadInfoType.tp_name == 0) >>> - PyStructSequence_InitType(&ThreadInfoType, &threadinfo_desc); >>> + if (ThreadInfoType.tp_name == 0) { >>> + if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) >>> < 0) >>> + return NULL; >>> + } >>> >>> threadinfo = PyStructSequence_New(&ThreadInfoType); >>> if (threadinfo == 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 >>> >> >> _______________________________________________ >> Python-Dev mailing list >> Python-Dev at python.org >> http://mail.python.org/mailman/listinfo/python-dev >> Unsubscribe: >> http://mail.python.org/mailman/options/python-dev/benjamin%40python.org >> > > > > -- > Regards, > Benjamin > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins From solipsis at pitrou.net Tue Jul 23 08:22:30 2013 From: solipsis at pitrou.net (Antoine Pitrou) Date: Tue, 23 Jul 2013 08:22:30 +0200 Subject: [Python-checkins] [Python-Dev] cpython: Issue #18520: Add a new PyStructSequence_InitType2() function, same than References: <3bzcCt6wttz7Ljj@mail.python.org> Message-ID: <20130723082230.57a5f5b2@fsol> On Tue, 23 Jul 2013 08:15:29 +0200 Ronald Oussoren wrote: > > On 23 Jul, 2013, at 2:01, Benjamin Peterson wrote: > > > We've cheerfully broken the ABI before on minor releases, though if > > it's part of the stable ABI, we can't be cavaliar about that anymore. > > It is not part of the stable ABI. Given that the implementation of > PyStructSequence_InitType() in the patch just calls PyStructSequence_InitType2() > and ignores the return value you could change the return value of ..InitType(). > > This may or may not break existing extensions using the function (depending on > platform ABI details, AFAIK this is not a problem on x86/x86_64), but reusing > extensions across python feature releases is not supported anyway. Not supported? It should certainly be supported accross bugfix versions. Otherwise, installing a new bugfix version would force you to recompile all independently-installed extension modules. Regards Antoine. From solipsis at pitrou.net Tue Jul 23 08:23:45 2013 From: solipsis at pitrou.net (Antoine Pitrou) Date: Tue, 23 Jul 2013 08:23:45 +0200 Subject: [Python-checkins] [Python-Dev] cpython: Issue #18520: Add a new PyStructSequence_InitType2() function, same than References: <3bzcCt6wttz7Ljj@mail.python.org> <20130723082230.57a5f5b2@fsol> Message-ID: <20130723082345.037d0921@fsol> On Tue, 23 Jul 2013 08:22:30 +0200 Antoine Pitrou wrote: > On Tue, 23 Jul 2013 08:15:29 +0200 > Ronald Oussoren wrote: > > > > On 23 Jul, 2013, at 2:01, Benjamin Peterson wrote: > > > > > We've cheerfully broken the ABI before on minor releases, though if > > > it's part of the stable ABI, we can't be cavaliar about that anymore. > > > > It is not part of the stable ABI. Given that the implementation of > > PyStructSequence_InitType() in the patch just calls PyStructSequence_InitType2() > > and ignores the return value you could change the return value of ..InitType(). > > > > This may or may not break existing extensions using the function (depending on > > platform ABI details, AFAIK this is not a problem on x86/x86_64), but reusing > > extensions across python feature releases is not supported anyway. > > Not supported? It should certainly be supported accross bugfix > versions. Otherwise, installing a new bugfix version would force you to > recompile all independently-installed extension modules. Ah, but I see that "minor release" was used in the sense of "feature release". My bad. (Grrr!) Regards Antoine. From christian at python.org Tue Jul 23 12:00:51 2013 From: christian at python.org (Christian Heimes) Date: Tue, 23 Jul 2013 12:00:51 +0200 Subject: [Python-checkins] cpython (3.3): return NULL here In-Reply-To: <3bznlW6d69z7LkD@mail.python.org> References: <3bznlW6d69z7LkD@mail.python.org> Message-ID: <51EE5453.4010209@python.org> Am 23.07.2013 07:08, schrieb benjamin.peterson: > http://hg.python.org/cpython/rev/042ff9325c5e > changeset: 84804:042ff9325c5e > branch: 3.3 > parent: 84789:bb63f813a00f > user: Benjamin Peterson > date: Mon Jul 22 22:08:09 2013 -0700 > summary: > return NULL here > > files: > Python/dynload_shlib.c | 3 ++- > 1 files changed, 2 insertions(+), 1 deletions(-) > > > diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c > --- a/Python/dynload_shlib.c > +++ b/Python/dynload_shlib.c > @@ -91,7 +91,8 @@ > int i; > struct stat statb; > if (fstat(fileno(fp), &statb) == -1) { > - return PyErr_SetFromErrno(PyExc_IOError); > + PyErr_SetFromErrno(PyExc_IOError); > + return NULL; > } PyErr_SetFromErrno() already and always returns NULL. Or do you prefer to return NULL explicitly? Christian From benjamin at python.org Tue Jul 23 17:10:40 2013 From: benjamin at python.org (Benjamin Peterson) Date: Tue, 23 Jul 2013 08:10:40 -0700 Subject: [Python-checkins] cpython (3.3): return NULL here In-Reply-To: <51EE5453.4010209@python.org> References: <3bznlW6d69z7LkD@mail.python.org> <51EE5453.4010209@python.org> Message-ID: 2013/7/23 Christian Heimes : > Am 23.07.2013 07:08, schrieb benjamin.peterson: >> http://hg.python.org/cpython/rev/042ff9325c5e >> changeset: 84804:042ff9325c5e >> branch: 3.3 >> parent: 84789:bb63f813a00f >> user: Benjamin Peterson >> date: Mon Jul 22 22:08:09 2013 -0700 >> summary: >> return NULL here >> >> files: >> Python/dynload_shlib.c | 3 ++- >> 1 files changed, 2 insertions(+), 1 deletions(-) >> >> >> diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c >> --- a/Python/dynload_shlib.c >> +++ b/Python/dynload_shlib.c >> @@ -91,7 +91,8 @@ >> int i; >> struct stat statb; >> if (fstat(fileno(fp), &statb) == -1) { >> - return PyErr_SetFromErrno(PyExc_IOError); >> + PyErr_SetFromErrno(PyExc_IOError); >> + return NULL; >> } > > PyErr_SetFromErrno() already and always returns NULL. Or do you prefer > to return NULL explicitly? It might always return NULL, but the compiler sees (PyObject *)NULL when this function returns dl_funcptr. -- Regards, Benjamin From christian at python.org Tue Jul 23 17:36:34 2013 From: christian at python.org (Christian Heimes) Date: Tue, 23 Jul 2013 17:36:34 +0200 Subject: [Python-checkins] cpython (3.3): return NULL here In-Reply-To: References: <3bznlW6d69z7LkD@mail.python.org> <51EE5453.4010209@python.org> Message-ID: <51EEA302.7070008@python.org> Am 23.07.2013 17:10, schrieb Benjamin Peterson: >> PyErr_SetFromErrno() already and always returns NULL. Or do you prefer >> to return NULL explicitly? > > It might always return NULL, but the compiler sees (PyObject *)NULL > when this function returns dl_funcptr. Oh, you are right. I must have missed the compiler warning. How about we turn type return and type assignment warnings into fatal errors? Christian From ronaldoussoren at mac.com Tue Jul 23 17:46:26 2013 From: ronaldoussoren at mac.com (Ronald Oussoren) Date: Tue, 23 Jul 2013 17:46:26 +0200 Subject: [Python-checkins] [Python-Dev] cpython (3.3): return NULL here In-Reply-To: <51EEA302.7070008@python.org> References: <3bznlW6d69z7LkD@mail.python.org> <51EE5453.4010209@python.org> <51EEA302.7070008@python.org> Message-ID: <9C38BD1B-24FF-4360-A729-6DC215238A6C@mac.com> On 23 Jul, 2013, at 17:36, Christian Heimes wrote: > Am 23.07.2013 17:10, schrieb Benjamin Peterson: >>> PyErr_SetFromErrno() already and always returns NULL. Or do you prefer >>> to return NULL explicitly? >> >> It might always return NULL, but the compiler sees (PyObject *)NULL >> when this function returns dl_funcptr. > > Oh, you are right. I must have missed the compiler warning. How about we > turn type return and type assignment warnings into fatal errors? That's probably possible with a '-Werror=....' argument. But please consider issue 18211 before unconditionally adding such a flag, as that issue mentions new compiler flags also get used when compiling 3th-party extensions. I guess there needs to be (yet) another CFLAGS_xxx variable in the Makefile that gets added to $(CFLAGS) during the build of Python itself, but is ignored by distutils and sysconfig. Ronald > > Christian > > _______________________________________________ > Python-Dev mailing list > Python-Dev at python.org > http://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: http://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com From solipsis at pitrou.net Wed Jul 24 05:54:27 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 24 Jul 2013 05:54:27 +0200 Subject: [Python-checkins] Daily reference leaks (a5681f50bae2): sum=-1 Message-ID: results for a5681f50bae2 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/reflogdKPWEk', '-x'] From greg at krypto.org Wed Jul 24 08:43:59 2013 From: greg at krypto.org (Gregory P. Smith) Date: Tue, 23 Jul 2013 23:43:59 -0700 Subject: [Python-checkins] [Python-Dev] cpython (3.3): return NULL here In-Reply-To: <9C38BD1B-24FF-4360-A729-6DC215238A6C@mac.com> References: <3bznlW6d69z7LkD@mail.python.org> <51EE5453.4010209@python.org> <51EEA302.7070008@python.org> <9C38BD1B-24FF-4360-A729-6DC215238A6C@mac.com> Message-ID: On Tue, Jul 23, 2013 at 8:46 AM, Ronald Oussoren wrote: > > On 23 Jul, 2013, at 17:36, Christian Heimes wrote: > > > Am 23.07.2013 17:10, schrieb Benjamin Peterson: > >>> PyErr_SetFromErrno() already and always returns NULL. Or do you prefer > >>> to return NULL explicitly? > >> > >> It might always return NULL, but the compiler sees (PyObject *)NULL > >> when this function returns dl_funcptr. > > > > Oh, you are right. I must have missed the compiler warning. How about we > > turn type return and type assignment warnings into fatal errors? > > That's probably possible with a '-Werror=....' argument. But please > consider > issue 18211 before unconditionally adding such a flag, as that issue > mentions > new compiler flags also get used when compiling 3th-party extensions. > > I guess there needs to be (yet) another CFLAGS_xxx variable in the > Makefile that > gets added to $(CFLAGS) during the build of Python itself, but is ignored > by > distutils and sysconfig. > It seems fair to turn those on in 3.4 and require that third party extensions clean up their code when porting from 3.3 to 3.4. > Ronald > > > > > Christian > > > > _______________________________________________ > > Python-Dev mailing list > > Python-Dev at python.org > > http://mail.python.org/mailman/listinfo/python-dev > > Unsubscribe: > http://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com > > _______________________________________________ > 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 ronaldoussoren at mac.com Wed Jul 24 09:01:30 2013 From: ronaldoussoren at mac.com (Ronald Oussoren) Date: Wed, 24 Jul 2013 09:01:30 +0200 Subject: [Python-checkins] [Python-Dev] cpython (3.3): return NULL here In-Reply-To: References: <3bznlW6d69z7LkD@mail.python.org> <51EE5453.4010209@python.org> <51EEA302.7070008@python.org> <9C38BD1B-24FF-4360-A729-6DC215238A6C@mac.com> Message-ID: <568DFFEE-F257-4EA2-A749-DA8BCECCDDF0@mac.com> On 24 Jul, 2013, at 8:43, Gregory P. Smith wrote: > > On Tue, Jul 23, 2013 at 8:46 AM, Ronald Oussoren wrote: > > On 23 Jul, 2013, at 17:36, Christian Heimes wrote: > > > Am 23.07.2013 17:10, schrieb Benjamin Peterson: > >>> PyErr_SetFromErrno() already and always returns NULL. Or do you prefer > >>> to return NULL explicitly? > >> > >> It might always return NULL, but the compiler sees (PyObject *)NULL > >> when this function returns dl_funcptr. > > > > Oh, you are right. I must have missed the compiler warning. How about we > > turn type return and type assignment warnings into fatal errors? > > That's probably possible with a '-Werror=....' argument. But please consider > issue 18211 before unconditionally adding such a flag, as that issue mentions > new compiler flags also get used when compiling 3th-party extensions. > > I guess there needs to be (yet) another CFLAGS_xxx variable in the Makefile that > gets added to $(CFLAGS) during the build of Python itself, but is ignored by > distutils and sysconfig. > > It seems fair to turn those on in 3.4 and require that third party extensions clean up their code when porting from 3.3 to 3.4. In this case its "just" code cleanup, the issue I filed (see above) is for another -Werror flag that causes compile errors with some valid C99 code that isn't valid C89. That's good for CPython itself because its source code is explicitly C89, but is not good when building 3th-party extensions. A proper fix requires tweaking the configure script, Makefile and distutils and that's not really a fun prospect ;-) Ronald > > > Ronald > > > > > Christian > > > > _______________________________________________ > > Python-Dev mailing list > > Python-Dev at python.org > > http://mail.python.org/mailman/listinfo/python-dev > > Unsubscribe: http://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > > _______________________________________________ > Python-Dev mailing list > Python-Dev at python.org > http://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: http://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com From solipsis at pitrou.net Wed Jul 24 10:17:59 2013 From: solipsis at pitrou.net (Antoine Pitrou) Date: Wed, 24 Jul 2013 10:17:59 +0200 Subject: [Python-checkins] cpython (3.3): return NULL here References: <3bznlW6d69z7LkD@mail.python.org> <51EE5453.4010209@python.org> <51EEA302.7070008@python.org> <9C38BD1B-24FF-4360-A729-6DC215238A6C@mac.com> <568DFFEE-F257-4EA2-A749-DA8BCECCDDF0@mac.com> Message-ID: <20130724101759.7f608f12@pitrou.net> Le Wed, 24 Jul 2013 09:01:30 +0200, Ronald Oussoren a ?crit : > > On 24 Jul, 2013, at 8:43, Gregory P. Smith wrote: > > > > > On Tue, Jul 23, 2013 at 8:46 AM, Ronald Oussoren > > wrote: > > > > On 23 Jul, 2013, at 17:36, Christian Heimes > > wrote: > > > > > Am 23.07.2013 17:10, schrieb Benjamin Peterson: > > >>> PyErr_SetFromErrno() already and always returns NULL. Or do you > > >>> prefer to return NULL explicitly? > > >> > > >> It might always return NULL, but the compiler sees (PyObject > > >> *)NULL when this function returns dl_funcptr. > > > > > > Oh, you are right. I must have missed the compiler warning. How > > > about we turn type return and type assignment warnings into fatal > > > errors? > > > > That's probably possible with a '-Werror=....' argument. But please > > consider issue 18211 before unconditionally adding such a flag, as > > that issue mentions new compiler flags also get used when compiling > > 3th-party extensions. > > > > I guess there needs to be (yet) another CFLAGS_xxx variable in the > > Makefile that gets added to $(CFLAGS) during the build of Python > > itself, but is ignored by distutils and sysconfig. > > > > It seems fair to turn those on in 3.4 and require that third party > > extensions clean up their code when porting from 3.3 to 3.4. > > In this case its "just" code cleanup, the issue I filed (see above) > is for another -Werror flag that causes compile errors with some > valid C99 code that isn't valid C89. That's good for CPython itself > because its source code is explicitly C89, but is not good when > building 3th-party extensions. Agreed. We shouldn't impose specific error flags on 3rd-party extension writers. Regards Antoine. From python-checkins at python.org Wed Jul 24 17:14:23 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 24 Jul 2013 17:14:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_ignore_*=7E?= Message-ID: <3c0g7z4GnGz7Ljd@mail.python.org> http://hg.python.org/devguide/rev/afc3c392b0bd changeset: 628:afc3c392b0bd user: Christian Heimes date: Wed Jul 24 17:11:24 2013 +0200 summary: ignore *~ files: .hgignore | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,4 +1,5 @@ syntax: glob *.swp +*~ _build -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jul 24 17:14:24 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 24 Jul 2013 17:14:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_First_draft_of_Coverity_s?= =?utf-8?q?ection_for_the_devguide=2E?= Message-ID: <3c0g8071JCz7Ljd@mail.python.org> http://hg.python.org/devguide/rev/0889b571e0aa changeset: 629:0889b571e0aa user: Christian Heimes date: Wed Jul 24 17:14:14 2013 +0200 summary: First draft of Coverity section for the devguide. Please feel free to improve my English. :) files: coverity.rst | 142 +++++++++++++++++++++++++++++++++++++++ index.rst | 2 + 2 files changed, 144 insertions(+), 0 deletions(-) diff --git a/coverity.rst b/coverity.rst new file mode 100644 --- /dev/null +++ b/coverity.rst @@ -0,0 +1,142 @@ +============= +Coverity Scan +============= + +.. _coverity: + +Coverity Scan is a free service for static code analysis of Open Source +projects. It is based on Coverity's commercial product and is able to analyze +C, C++ and Java code. + +Coverity's static code analysis doesn't run the code. Instead of that it uses +abstract interpretation to gain information about the code's control flow and +data flow. It's able to follow all possible code paths that a program may +take. For example the analyzer understands that ``malloc()`` returns a memory +that must be freed with ``free()`` later. It follows all branches and function +calls to see if all possible combinations free the memory. The analyzer is +able to detect all sorts of issues like resource leaks (memory, file +descriptors), NULL dereferencing, use after free, unchecked return values, +dead code, buffer overflows, integer overflows, uninitialized variables, and +many more. + + +Access to analysis reports +========================== + +The results are available on the `Coverity Scan`_ website. In order to +access the results you have to create an account yourself. Then go to +*Projects using Scan* and add yourself to the Python project. New members must +be approved by an admin (see `Contact`_). + +Access is restricted to Python core developers only. Other individuals may be +given access at our own discretion, too. Every now and then Coverity detects a +critical issue in Python's code -- new analyzers may even find new bugs in +mature code. We don't want to disclose issues prematurely. + + +Building and uploading analysis +=============================== + +The process is automated. Twice a day a script runs ``hg checkout``, +``cov-build`` and uploads the latest analysis to Coverity. The build runs on a +dedicated virtual machine on PSF's infrastructure at OSU Open Source Labs. The +process is maintained by Christian Heimes (see `Contact`_). At present only +the tip is analyzed with the 64bit Linux tools. + + +Known limitations +================= + +Some aspects of Python's C code are not yet understood by Coverity. + +False positives +--------------- + +``Py_BuildValue("N", PyObject*)`` + Coverity doesn't understand that ``N`` format char passes the object along + without touching its reference count. On this ground the analyzer detects + a resource leak. CID 719685 + +``PyLong_FromLong(-1)`` + Coverity claims that ``PyLong_FromLong()`` and other ``PyLong_From*()`` + functions cannot handle a negative value because the value might be used as + an array index in ``get_small_int()``. CID 486783 + +``PyArg_ParseTupleAndKeywords(args, kwargs, "s#", &data, &length)`` + Some functions use the format char combination such as ``s#``, ``u#`` or + ``z#`` to get data and length of a character array. Coverity doesn't + recognize the relation between data and length. Sometimes it detects a buffer + overflow if data is written to a fixed size buffer although + ``length <= sizeof(buffer)``. CID 486613 + +Intentionally +------------- + +``Py_VA_COPY()`` + Python is written in C89 (ANSI C), therefore it can't use C99 features such + as ``va_copy()``. Python's own variant ``Py_VA_COPY()`` uses ``memcpy()`` + to make a copy of a ``va_list`` variable. Coverity detects two issues in + this approach: "Passing argument "lva" of type "va_list" and sizeof(va_list) + to function memcpy() is suspicious." CID 486405 and "Uninitialized pointer + read" CID 486630. + + +Modeling +======== + +Modeling is explained in the *Coverity Help Center* which is available in +the help menu of `Coverity Connect`_. `coverity_model.c`_ contains a copy of +Python's modeling file for Coverity. Please keep the copy in sync with the +model file in *Analysis Settings* of `Coverity Scan`_. + + +Workflow +======== + +False positive and intentional issues +------------------------------------- + +If the problem is listed under `Known limitations`_ then please set the +classification to either "False positive" or "Intentional", the action to +"Ignore", owner to your own account and add a comment why the issue +is considered false positive or intentional. + +If you think it's a new false positive or intentional then please contact an +admin. The first step should be an updated to Python's `Modeling`_ file. + + +Positive issues +--------------- + +You should always create an issue unless it's really a trivial case. Please +add the full url to the ticket under *Ext. Reference* and add the CID +(Coverity ID) to both the ticket and the checkin message. It makes it much +easier to understand the relation between tickets, fixes and Coverity issues. + + +Contact +======= + +Please include both Brett and Christian in any mail regarding Coverity. Mails +to Coverity should go through Brett or Christian, too. + +Christian Heimes + admin, maintainer of build machine, intermediary between Python and Coverity + +Brett Cannon + co-admin + +Dakshesh Vyas + Technical Manager - Coverity Scan + + +.. seealso:: + + `Coverity Scan FAQ `_ + + +.. _Coverity Scan: http://scan.coverity.com/ + +.. _Coverity Connect: http://scan5.coverity.com:8080/ + +.. _coverity_model.c: http://hg.python.org/cpython/file/tip/Misc/coverity_model.c diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -80,6 +80,7 @@ * :doc:`committing` * :doc:`devcycle` * :doc:`buildbots` + * :doc:`coverity` It is **recommended** that the above documents be read in the order listed. You can stop where you feel comfortable and begin contributing immediately without @@ -203,6 +204,7 @@ gdb grammar compiler + coverity faq -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jul 24 18:53:17 2013 From: python-checkins at python.org (vinay.sajip) Date: Wed, 24 Jul 2013 18:53:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NTQx?= =?utf-8?q?=3A_simplified_LoggerAdapter_example=2E?= Message-ID: <3c0jL5285PzQlq@mail.python.org> http://hg.python.org/cpython/rev/16c15d7d4480 changeset: 84806:16c15d7d4480 branch: 2.7 parent: 84779:e8b8279ca118 user: Vinay Sajip date: Wed Jul 24 17:47:52 2013 +0100 summary: Issue #18541: simplified LoggerAdapter example. files: Doc/howto/logging-cookbook.rst | 76 +++++---------------- 1 files changed, 19 insertions(+), 57 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -460,69 +460,31 @@ the keys of the dict-like object. If you need a different method, e.g. if you want to prepend or append the contextual information to the message string, you just need to subclass :class:`LoggerAdapter` and override :meth:`process` -to do what you need. Here's an example script which uses this class, which -also illustrates what dict-like behaviour is needed from an arbitrary -'dict-like' object for use in the constructor:: +to do what you need. Here is a simple example:: - import logging + class CustomAdapter(logging.LoggerAdapter): + """ + This example adapter expects the passed in dict-like object to have a + 'connid' key, whose value in brackets is prepended to the log message. + """ + def process(self, msg, kwargs): + return '[%s] %s' % (self.extra['connid'], msg), kwargs - class ConnInfo: - """ - An example class which shows how an arbitrary class can be used as - the 'extra' context information repository passed to a LoggerAdapter. - """ +which you can use like this:: - def __getitem__(self, name): - """ - To allow this instance to look like a dict. - """ - from random import choice - if name == 'ip': - result = choice(['127.0.0.1', '192.168.0.1']) - elif name == 'user': - result = choice(['jim', 'fred', 'sheila']) - else: - result = self.__dict__.get(name, '?') - return result + logger = logging.getLogger(__name__) + adapter = CustomAdapter(logger, {'connid': some_conn_id}) - def __iter__(self): - """ - To allow iteration over keys, which will be merged into - the LogRecord dict before formatting and output. - """ - keys = ['ip', 'user'] - keys.extend(self.__dict__.keys()) - return keys.__iter__() +Then any events that you log to the adapter will have the value of +``some_conn_id`` prepended to the log messages. - if __name__ == '__main__': - from random import choice - levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) - a1 = logging.LoggerAdapter(logging.getLogger('a.b.c'), - { 'ip' : '123.231.231.123', 'user' : 'sheila' }) - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s') - a1.debug('A debug message') - a1.info('An info message with %s', 'some parameters') - a2 = logging.LoggerAdapter(logging.getLogger('d.e.f'), ConnInfo()) - for x in range(10): - lvl = choice(levels) - lvlname = logging.getLevelName(lvl) - a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters') +Using objects other than dicts to pass contextual information +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When this script is run, the output should look something like this:: - - 2008-01-18 14:49:54,023 a.b.c DEBUG IP: 123.231.231.123 User: sheila A debug message - 2008-01-18 14:49:54,023 a.b.c INFO IP: 123.231.231.123 User: sheila An info message with some parameters - 2008-01-18 14:49:54,023 d.e.f CRITICAL IP: 192.168.0.1 User: jim A message at CRITICAL level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: jim A message at INFO level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: fred A message at ERROR level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: sheila A message at ERROR level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: jim A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: fred A message at INFO level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 127.0.0.1 User: jim A message at WARNING level with 2 parameters +You don't need to pass an actual dict to a :class:`LoggerAdapter` - you could +pass an instance of a class which implements ``__getitem__`` and ``__iter__`` so +that it looks like a dict to logging. This would be useful if you want to +generate values dynamically (whereas the values in a dict would be constant). .. _filters-contextual: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 24 18:53:18 2013 From: python-checkins at python.org (vinay.sajip) Date: Wed, 24 Jul 2013 18:53:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTQx?= =?utf-8?q?=3A_simplified_LoggerAdapter_example=2E?= Message-ID: <3c0jL65GySz7LkG@mail.python.org> http://hg.python.org/cpython/rev/adaecee37745 changeset: 84807:adaecee37745 branch: 3.3 parent: 84804:042ff9325c5e user: Vinay Sajip date: Wed Jul 24 17:52:01 2013 +0100 summary: Issue #18541: simplified LoggerAdapter example. files: Doc/howto/logging-cookbook.rst | 76 +++++---------------- 1 files changed, 19 insertions(+), 57 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -524,69 +524,31 @@ the keys of the dict-like object. If you need a different method, e.g. if you want to prepend or append the contextual information to the message string, you just need to subclass :class:`LoggerAdapter` and override :meth:`process` -to do what you need. Here's an example script which uses this class, which -also illustrates what dict-like behaviour is needed from an arbitrary -'dict-like' object for use in the constructor:: +to do what you need. Here is a simple example:: - import logging + class CustomAdapter(logging.LoggerAdapter): + """ + This example adapter expects the passed in dict-like object to have a + 'connid' key, whose value in brackets is prepended to the log message. + """ + def process(self, msg, kwargs): + return '[%s] %s' % (self.extra['connid'], msg), kwargs - class ConnInfo: - """ - An example class which shows how an arbitrary class can be used as - the 'extra' context information repository passed to a LoggerAdapter. - """ +which you can use like this:: - def __getitem__(self, name): - """ - To allow this instance to look like a dict. - """ - from random import choice - if name == 'ip': - result = choice(['127.0.0.1', '192.168.0.1']) - elif name == 'user': - result = choice(['jim', 'fred', 'sheila']) - else: - result = self.__dict__.get(name, '?') - return result + logger = logging.getLogger(__name__) + adapter = CustomAdapter(logger, {'connid': some_conn_id}) - def __iter__(self): - """ - To allow iteration over keys, which will be merged into - the LogRecord dict before formatting and output. - """ - keys = ['ip', 'user'] - keys.extend(self.__dict__.keys()) - return keys.__iter__() +Then any events that you log to the adapter will have the value of +``some_conn_id`` prepended to the log messages. - if __name__ == '__main__': - from random import choice - levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) - a1 = logging.LoggerAdapter(logging.getLogger('a.b.c'), - { 'ip' : '123.231.231.123', 'user' : 'sheila' }) - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s') - a1.debug('A debug message') - a1.info('An info message with %s', 'some parameters') - a2 = logging.LoggerAdapter(logging.getLogger('d.e.f'), ConnInfo()) - for x in range(10): - lvl = choice(levels) - lvlname = logging.getLevelName(lvl) - a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters') +Using objects other than dicts to pass contextual information +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When this script is run, the output should look something like this:: - - 2008-01-18 14:49:54,023 a.b.c DEBUG IP: 123.231.231.123 User: sheila A debug message - 2008-01-18 14:49:54,023 a.b.c INFO IP: 123.231.231.123 User: sheila An info message with some parameters - 2008-01-18 14:49:54,023 d.e.f CRITICAL IP: 192.168.0.1 User: jim A message at CRITICAL level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: jim A message at INFO level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: fred A message at ERROR level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: sheila A message at ERROR level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: jim A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: fred A message at INFO level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 127.0.0.1 User: jim A message at WARNING level with 2 parameters +You don't need to pass an actual dict to a :class:`LoggerAdapter` - you could +pass an instance of a class which implements ``__getitem__`` and ``__iter__`` so +that it looks like a dict to logging. This would be useful if you want to +generate values dynamically (whereas the values in a dict would be constant). .. _filters-contextual: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 24 18:53:20 2013 From: python-checkins at python.org (vinay.sajip) Date: Wed, 24 Jul 2013 18:53:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2318541=3A_merged_update_from_3=2E3=2E?= Message-ID: <3c0jL81Bs8zQ16@mail.python.org> http://hg.python.org/cpython/rev/f931ee89cc1c changeset: 84808:f931ee89cc1c parent: 84805:a5681f50bae2 parent: 84807:adaecee37745 user: Vinay Sajip date: Wed Jul 24 17:52:58 2013 +0100 summary: Closes #18541: merged update from 3.3. files: Doc/howto/logging-cookbook.rst | 76 +++++---------------- 1 files changed, 19 insertions(+), 57 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -524,69 +524,31 @@ the keys of the dict-like object. If you need a different method, e.g. if you want to prepend or append the contextual information to the message string, you just need to subclass :class:`LoggerAdapter` and override :meth:`process` -to do what you need. Here's an example script which uses this class, which -also illustrates what dict-like behaviour is needed from an arbitrary -'dict-like' object for use in the constructor:: +to do what you need. Here is a simple example:: - import logging + class CustomAdapter(logging.LoggerAdapter): + """ + This example adapter expects the passed in dict-like object to have a + 'connid' key, whose value in brackets is prepended to the log message. + """ + def process(self, msg, kwargs): + return '[%s] %s' % (self.extra['connid'], msg), kwargs - class ConnInfo: - """ - An example class which shows how an arbitrary class can be used as - the 'extra' context information repository passed to a LoggerAdapter. - """ +which you can use like this:: - def __getitem__(self, name): - """ - To allow this instance to look like a dict. - """ - from random import choice - if name == 'ip': - result = choice(['127.0.0.1', '192.168.0.1']) - elif name == 'user': - result = choice(['jim', 'fred', 'sheila']) - else: - result = self.__dict__.get(name, '?') - return result + logger = logging.getLogger(__name__) + adapter = CustomAdapter(logger, {'connid': some_conn_id}) - def __iter__(self): - """ - To allow iteration over keys, which will be merged into - the LogRecord dict before formatting and output. - """ - keys = ['ip', 'user'] - keys.extend(self.__dict__.keys()) - return keys.__iter__() +Then any events that you log to the adapter will have the value of +``some_conn_id`` prepended to the log messages. - if __name__ == '__main__': - from random import choice - levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) - a1 = logging.LoggerAdapter(logging.getLogger('a.b.c'), - { 'ip' : '123.231.231.123', 'user' : 'sheila' }) - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s') - a1.debug('A debug message') - a1.info('An info message with %s', 'some parameters') - a2 = logging.LoggerAdapter(logging.getLogger('d.e.f'), ConnInfo()) - for x in range(10): - lvl = choice(levels) - lvlname = logging.getLevelName(lvl) - a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters') +Using objects other than dicts to pass contextual information +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When this script is run, the output should look something like this:: - - 2008-01-18 14:49:54,023 a.b.c DEBUG IP: 123.231.231.123 User: sheila A debug message - 2008-01-18 14:49:54,023 a.b.c INFO IP: 123.231.231.123 User: sheila An info message with some parameters - 2008-01-18 14:49:54,023 d.e.f CRITICAL IP: 192.168.0.1 User: jim A message at CRITICAL level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: jim A message at INFO level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: fred A message at ERROR level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: sheila A message at ERROR level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: jim A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: fred A message at INFO level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters - 2008-01-18 14:49:54,033 d.e.f WARNING IP: 127.0.0.1 User: jim A message at WARNING level with 2 parameters +You don't need to pass an actual dict to a :class:`LoggerAdapter` - you could +pass an instance of a class which implements ``__getitem__`` and ``__iter__`` so +that it looks like a dict to logging. This would be useful if you want to +generate values dynamically (whereas the values in a dict would be constant). .. _filters-contextual: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 24 20:39:26 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 24 Jul 2013 20:39:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_document_path=5Fconverter?= =?utf-8?q?=28=29_issue?= Message-ID: <3c0lhZ5Ljwz7LjY@mail.python.org> http://hg.python.org/devguide/rev/f0fa852d6eba changeset: 630:f0fa852d6eba user: Christian Heimes date: Wed Jul 24 20:39:19 2013 +0200 summary: document path_converter() issue files: coverity.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/coverity.rst b/coverity.rst --- a/coverity.rst +++ b/coverity.rst @@ -69,6 +69,12 @@ overflow if data is written to a fixed size buffer although ``length <= sizeof(buffer)``. CID 486613 +``path_converter()`` dereferencing after null check + The ``path_converter()`` function in ``posixmodule.c`` makes sure that + either ``path_t.narrow`` or ``path_t.wide`` is filled unless + ``path_t.nullable`` is explicitly enabled. CID 719648 + + Intentionally ------------- -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jul 24 21:03:40 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 24 Jul 2013 21:03:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_potential_?= =?utf-8?q?NULL_pointer_dereferencing_in_ast_module?= Message-ID: <3c0mDX0ZKszQTd@mail.python.org> http://hg.python.org/cpython/rev/0ac424c86a94 changeset: 84809:0ac424c86a94 branch: 3.3 parent: 84807:adaecee37745 user: Christian Heimes date: Wed Jul 24 21:02:17 2013 +0200 summary: Fix potential NULL pointer dereferencing in ast module CID 719690 files: Python/ast.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -535,11 +535,11 @@ if (!c->c_normalize) return 0; c->c_normalize_args = Py_BuildValue("(sN)", "NFKC", Py_None); - PyTuple_SET_ITEM(c->c_normalize_args, 1, NULL); if (!c->c_normalize_args) { Py_CLEAR(c->c_normalize); return 0; } + PyTuple_SET_ITEM(c->c_normalize_args, 1, NULL); return 1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 24 21:03:41 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 24 Jul 2013 21:03:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_potential_NULL_pointer_dereferencing_in_ast_module?= Message-ID: <3c0mDY2ZlBzSX6@mail.python.org> http://hg.python.org/cpython/rev/96d817f41c4c changeset: 84810:96d817f41c4c parent: 84808:f931ee89cc1c parent: 84809:0ac424c86a94 user: Christian Heimes date: Wed Jul 24 21:02:50 2013 +0200 summary: Fix potential NULL pointer dereferencing in ast module CID 719690 files: Python/ast.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -528,11 +528,11 @@ if (!c->c_normalize) return 0; c->c_normalize_args = Py_BuildValue("(sN)", "NFKC", Py_None); - PyTuple_SET_ITEM(c->c_normalize_args, 1, NULL); if (!c->c_normalize_args) { Py_CLEAR(c->c_normalize); return 0; } + PyTuple_SET_ITEM(c->c_normalize_args, 1, NULL); return 1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 24 23:50:42 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 24 Jul 2013 23:50:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Checkout_is_an_subversion?= =?utf-8?q?_term=2E_The_script_actually_runs_hg_pull_and_hg_update=2E?= Message-ID: <3c0qxG4vFLzRJ0@mail.python.org> http://hg.python.org/devguide/rev/a12dca777753 changeset: 631:a12dca777753 user: Christian Heimes date: Wed Jul 24 23:50:34 2013 +0200 summary: Checkout is an subversion term. The script actually runs hg pull and hg update. files: coverity.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/coverity.rst b/coverity.rst --- a/coverity.rst +++ b/coverity.rst @@ -37,7 +37,7 @@ Building and uploading analysis =============================== -The process is automated. Twice a day a script runs ``hg checkout``, +The process is automated. Twice a day a script runs ``hg pull``, ``hg update`` ``cov-build`` and uploads the latest analysis to Coverity. The build runs on a dedicated virtual machine on PSF's infrastructure at OSU Open Source Labs. The process is maintained by Christian Heimes (see `Contact`_). At present only -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jul 25 05:05:15 2013 From: python-checkins at python.org (ezio.melotti) Date: Thu, 25 Jul 2013 05:05:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE2OTM3OiBkb2N1?= =?utf-8?q?ment_that_stdin_is_always_buffered=2C_even_when_-u_is_used=2E__?= =?utf-8?q?Patch_by?= Message-ID: <3c0ywC4qSyzQGZ@mail.python.org> http://hg.python.org/cpython/rev/4b33f74ab0f1 changeset: 84811:4b33f74ab0f1 branch: 3.3 parent: 84809:0ac424c86a94 user: Ezio Melotti date: Thu Jul 25 05:04:02 2013 +0200 summary: #16937: document that stdin is always buffered, even when -u is used. Patch by Elena Oat. files: Doc/using/cmdline.rst | 4 ++-- Misc/ACKS | 1 + Misc/python.man | 3 ++- Modules/main.c | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -269,8 +269,8 @@ .. cmdoption:: -u - Force the binary layer of the stdin, stdout and stderr streams (which is - available as their ``buffer`` attribute) to be unbuffered. The text I/O + Force the binary layer of the stdout and stderr streams (which is + available as their ``buffer`` attribute) to be unbuffered. The text I/O layer will still be line-buffered if writing to the console, or block-buffered if redirected to a non-interactive file. diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -896,6 +896,7 @@ Zooko O'Whielacronx Aaron Oakley James Oakley +Elena Oat Jon Oberheide Pascal Oberndoerfer Jeffrey Ollie diff --git a/Misc/python.man b/Misc/python.man --- a/Misc/python.man +++ b/Misc/python.man @@ -172,7 +172,8 @@ is explicitly imported later. .TP .B \-u -Force the binary I/O layers of stdin, stdout and stderr to be unbuffered. +Force the binary I/O layers of stdout and stderr to be unbuffered. +stdin is always buffered. The text I/O layer will still be line-buffered. .\" Note that there is internal buffering in readlines() and .\" file-object iterators ("for line in sys.stdin") which is not diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -77,7 +77,8 @@ -S : don't imply 'import site' on initialization\n\ "; static char *usage_3 = "\ --u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x\n\ +-u : unbuffered binary stdout and stderr, stdin always buffered;\n\ + also PYTHONUNBUFFERED=x\n\ see man page for details on internal buffering relating to '-u'\n\ -v : verbose (trace import statements); also PYTHONVERBOSE=x\n\ can be supplied multiple times to increase verbosity\n\ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 05:05:16 2013 From: python-checkins at python.org (ezio.melotti) Date: Thu, 25 Jul 2013 05:05:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE2OTM3OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3c0ywD6sqrzRbZ@mail.python.org> http://hg.python.org/cpython/rev/52f0aa0d552a changeset: 84812:52f0aa0d552a parent: 84810:96d817f41c4c parent: 84811:4b33f74ab0f1 user: Ezio Melotti date: Thu Jul 25 05:04:50 2013 +0200 summary: #16937: merge with 3.3. files: Doc/using/cmdline.rst | 4 ++-- Misc/ACKS | 1 + Misc/python.man | 3 ++- Modules/main.c | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -274,8 +274,8 @@ .. cmdoption:: -u - Force the binary layer of the stdin, stdout and stderr streams (which is - available as their ``buffer`` attribute) to be unbuffered. The text I/O + Force the binary layer of the stdout and stderr streams (which is + available as their ``buffer`` attribute) to be unbuffered. The text I/O layer will still be line-buffered if writing to the console, or block-buffered if redirected to a non-interactive file. diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -921,6 +921,7 @@ Zooko O'Whielacronx Aaron Oakley James Oakley +Elena Oat Jon Oberheide Pascal Oberndoerfer Jeffrey Ollie diff --git a/Misc/python.man b/Misc/python.man --- a/Misc/python.man +++ b/Misc/python.man @@ -172,7 +172,8 @@ is explicitly imported later. .TP .B \-u -Force the binary I/O layers of stdin, stdout and stderr to be unbuffered. +Force the binary I/O layers of stdout and stderr to be unbuffered. +stdin is always buffered. The text I/O layer will still be line-buffered. .\" Note that there is internal buffering in readlines() and .\" file-object iterators ("for line in sys.stdin") which is not diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -73,7 +73,8 @@ -S : don't imply 'import site' on initialization\n\ "; static char *usage_3 = "\ --u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x\n\ +-u : unbuffered binary stdout and stderr, stdin always buffered;\n\ + also PYTHONUNBUFFERED=x\n\ see man page for details on internal buffering relating to '-u'\n\ -v : verbose (trace import statements); also PYTHONVERBOSE=x\n\ can be supplied multiple times to increase verbosity\n\ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 05:25:06 2013 From: python-checkins at python.org (ezio.melotti) Date: Thu, 25 Jul 2013 05:25:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE0ODUzOiByZW1v?= =?utf-8?q?ve_test_that_was_making_too_many_assumptions_about_stdin=2E__Pa?= =?utf-8?q?tch_by?= Message-ID: <3c0zM66YhVzSg3@mail.python.org> http://hg.python.org/cpython/rev/17542d36effd changeset: 84813:17542d36effd branch: 2.7 parent: 84806:16c15d7d4480 user: Ezio Melotti date: Thu Jul 25 05:21:00 2013 +0200 summary: #14853: remove test that was making too many assumptions about stdin. Patch by Elena Oat. files: Lib/test/test_file.py | 10 ---------- Misc/ACKS | 1 + 2 files changed, 1 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py --- a/Lib/test/test_file.py +++ b/Lib/test/test_file.py @@ -154,16 +154,6 @@ f.close() self.fail('%r is an invalid file mode' % mode) - def testStdin(self): - # This causes the interpreter to exit on OSF1 v5.1. - if sys.platform != 'osf1V5': - self.assertRaises((IOError, ValueError), sys.stdin.seek, -1) - else: - print(( - ' Skipping sys.stdin.seek(-1), it may crash the interpreter.' - ' Test manually.'), file=sys.__stdout__) - self.assertRaises((IOError, ValueError), sys.stdin.truncate) - def testBadModeArgument(self): # verify that we get a sensible error message for bad mode argument bad_mode = "qwerty" diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -744,6 +744,7 @@ Kevin O'Connor Tim O'Malley Zooko O'Whielacronx +Elena Oat Pascal Oberndoerfer Jeffrey Ollie Adam Olsen -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 05:25:08 2013 From: python-checkins at python.org (ezio.melotti) Date: Thu, 25 Jul 2013 05:25:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE0ODUzOiByZW1v?= =?utf-8?q?ve_test_that_was_making_too_many_assumptions_about_stdin=2E__Pa?= =?utf-8?q?tch_by?= Message-ID: <3c0zM81XnrzSkV@mail.python.org> http://hg.python.org/cpython/rev/c5d847ee354a changeset: 84814:c5d847ee354a branch: 3.3 parent: 84811:4b33f74ab0f1 user: Ezio Melotti date: Thu Jul 25 05:21:00 2013 +0200 summary: #14853: remove test that was making too many assumptions about stdin. Patch by Elena Oat. files: Lib/test/test_file.py | 10 ---------- 1 files changed, 0 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py --- a/Lib/test/test_file.py +++ b/Lib/test/test_file.py @@ -148,16 +148,6 @@ f.close() self.fail('%r is an invalid file mode' % mode) - def testStdin(self): - # This causes the interpreter to exit on OSF1 v5.1. - if sys.platform != 'osf1V5': - self.assertRaises((IOError, ValueError), sys.stdin.seek, -1) - else: - print(( - ' Skipping sys.stdin.seek(-1), it may crash the interpreter.' - ' Test manually.'), file=sys.__stdout__) - self.assertRaises((IOError, ValueError), sys.stdin.truncate) - def testBadModeArgument(self): # verify that we get a sensible error message for bad mode argument bad_mode = "qwerty" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 05:25:09 2013 From: python-checkins at python.org (ezio.melotti) Date: Thu, 25 Jul 2013 05:25:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE0ODUzOiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3c0zM93NJfz7Ljm@mail.python.org> http://hg.python.org/cpython/rev/1d0ff57e392e changeset: 84815:1d0ff57e392e parent: 84812:52f0aa0d552a parent: 84814:c5d847ee354a user: Ezio Melotti date: Thu Jul 25 05:24:47 2013 +0200 summary: #14853: merge with 3.3. files: Lib/test/test_file.py | 10 ---------- 1 files changed, 0 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py --- a/Lib/test/test_file.py +++ b/Lib/test/test_file.py @@ -148,16 +148,6 @@ f.close() self.fail('%r is an invalid file mode' % mode) - def testStdin(self): - # This causes the interpreter to exit on OSF1 v5.1. - if sys.platform != 'osf1V5': - self.assertRaises((OSError, ValueError), sys.stdin.seek, -1) - else: - print(( - ' Skipping sys.stdin.seek(-1), it may crash the interpreter.' - ' Test manually.'), file=sys.__stdout__) - self.assertRaises((OSError, ValueError), sys.stdin.truncate) - def testBadModeArgument(self): # verify that we get a sensible error message for bad mode argument bad_mode = "qwerty" -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jul 25 05:57:42 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 25 Jul 2013 05:57:42 +0200 Subject: [Python-checkins] Daily reference leaks (96d817f41c4c): sum=0 Message-ID: results for 96d817f41c4c on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogjfm2x8', '-x'] From python-checkins at python.org Thu Jul 25 11:47:35 2013 From: python-checkins at python.org (christian.heimes) Date: Thu, 25 Jul 2013 11:47:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTQ5?= =?utf-8?q?=3A_Eliminate_dead_code_in_socket=5Fntohl=28=29=2E?= Message-ID: <3c17rR3fptzSRH@mail.python.org> http://hg.python.org/cpython/rev/b7ea3f94f6ca changeset: 84816:b7ea3f94f6ca branch: 3.3 parent: 84814:c5d847ee354a user: Christian Heimes date: Thu Jul 25 11:46:10 2013 +0200 summary: Issue #18549: Eliminate dead code in socket_ntohl(). CID 982369 files: Misc/NEWS | 2 ++ Modules/socketmodule.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,8 @@ Library ------- +- Issue #18549: Eliminate dead code in socket_ntohl() + - Issue #18514: Fix unreachable Py_DECREF() call in PyCData_FromBaseObj() - Issue #18513: Fix behaviour of cmath.rect w.r.t. signed zeros on OS X 10.8 + diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4702,8 +4702,6 @@ return PyErr_Format(PyExc_TypeError, "expected int/long, %s found", Py_TYPE(arg)->tp_name); - if (x == (unsigned long) -1 && PyErr_Occurred()) - return NULL; return PyLong_FromUnsignedLong(ntohl(x)); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 11:47:36 2013 From: python-checkins at python.org (christian.heimes) Date: Thu, 25 Jul 2013 11:47:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318549=3A_Eliminate_dead_code_in_socket=5Fntohl?= =?utf-8?b?KCku?= Message-ID: <3c17rS5ppyzRTT@mail.python.org> http://hg.python.org/cpython/rev/2a59428dbff5 changeset: 84817:2a59428dbff5 parent: 84815:1d0ff57e392e parent: 84816:b7ea3f94f6ca user: Christian Heimes date: Thu Jul 25 11:47:25 2013 +0200 summary: Issue #18549: Eliminate dead code in socket_ntohl(). CID 982369 files: Misc/NEWS | 2 ++ Modules/socketmodule.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -166,6 +166,8 @@ Library ------- +- Issue #18549: Eliminate dead code in socket_ntohl() + - Issue #18530: Remove additional stat call from posixpath.ismount. Patch by Alex Gaynor. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4663,8 +4663,6 @@ return PyErr_Format(PyExc_TypeError, "expected int/long, %s found", Py_TYPE(arg)->tp_name); - if (x == (unsigned long) -1 && PyErr_Occurred()) - return NULL; return PyLong_FromUnsignedLong(ntohl(x)); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 12:21:07 2013 From: python-checkins at python.org (vinay.sajip) Date: Thu, 25 Jul 2013 12:21:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2318491=3A_Added_s?= =?utf-8?q?cript-wrapper_functionality_to_launcher_source_=28but_not?= Message-ID: <3c18b76snYzMjB@mail.python.org> http://hg.python.org/cpython/rev/4123e002a1af changeset: 84818:4123e002a1af user: Vinay Sajip date: Thu Jul 25 11:20:55 2013 +0100 summary: Closes #18491: Added script-wrapper functionality to launcher source (but not to executable). files: PC/launcher.c | 172 ++++++++++++++++++++++++++++++------- 1 files changed, 138 insertions(+), 34 deletions(-) diff --git a/PC/launcher.c b/PC/launcher.c --- a/PC/launcher.c +++ b/PC/launcher.c @@ -20,6 +20,27 @@ #define SKIP_PREFIX #define SEARCH_PATH +/* Error codes */ + +#define RC_NO_STD_HANDLES 100 +#define RC_CREATE_PROCESS 101 +#define RC_BAD_VIRTUAL_PATH 102 +#define RC_NO_PYTHON 103 +#define RC_NO_MEMORY 104 +/* + * SCRIPT_WRAPPER is used to choose between two variants of an executable built + * from this source file. If not defined, the PEP 397 Python launcher is built; + * if defined, a script launcher of the type used by setuptools is built, which + * looks for a script name related to the executable name and runs that script + * with the appropriate Python interpreter. + * + * SCRIPT_WRAPPER should be undefined in the source, and defined in a VS project + * which builds the setuptools-style launcher. + */ +#if defined(SCRIPT_WRAPPER) +#define RC_NO_SCRIPT 105 +#endif + /* Just for now - static definition */ static FILE * log_fp = NULL; @@ -32,32 +53,6 @@ return p; } -/* - * This function is here to simplify memory management - * and to treat blank values as if they are absent. - */ -static wchar_t * get_env(wchar_t * key) -{ - /* This is not thread-safe, just like getenv */ - static wchar_t buf[256]; - DWORD result = GetEnvironmentVariableW(key, buf, 256); - - if (result > 255) { - /* Large environment variable. Accept some leakage */ - wchar_t *buf2 = (wchar_t*)malloc(sizeof(wchar_t) * (result+1)); - GetEnvironmentVariableW(key, buf2, result); - return buf2; - } - - if (result == 0) - /* Either some error, e.g. ERROR_ENVVAR_NOT_FOUND, - or an empty environment variable. */ - return NULL; - - return buf; -} - - static void debug(wchar_t * format, ...) { @@ -100,11 +95,40 @@ #if !defined(_WINDOWS) fwprintf(stderr, L"%s\n", message); #else - MessageBox(NULL, message, TEXT("Python Launcher is sorry to say ..."), MB_OK); + MessageBox(NULL, message, TEXT("Python Launcher is sorry to say ..."), + MB_OK); #endif ExitProcess(rc); } +/* + * This function is here to simplify memory management + * and to treat blank values as if they are absent. + */ +static wchar_t * get_env(wchar_t * key) +{ + /* This is not thread-safe, just like getenv */ + static wchar_t buf[BUFSIZE]; + DWORD result = GetEnvironmentVariableW(key, buf, BUFSIZE); + + if (result >= BUFSIZE) { + /* Large environment variable. Accept some leakage */ + wchar_t *buf2 = (wchar_t*)malloc(sizeof(wchar_t) * (result+1)); + if (buf2 = NULL) { + error(RC_NO_MEMORY, L"Could not allocate environment buffer"); + } + GetEnvironmentVariableW(key, buf2, result); + return buf2; + } + + if (result == 0) + /* Either some error, e.g. ERROR_ENVVAR_NOT_FOUND, + or an empty environment variable. */ + return NULL; + + return buf; +} + #if defined(_WINDOWS) #define PYTHON_EXECUTABLE L"pythonw.exe" @@ -115,11 +139,6 @@ #endif -#define RC_NO_STD_HANDLES 100 -#define RC_CREATE_PROCESS 101 -#define RC_BAD_VIRTUAL_PATH 102 -#define RC_NO_PYTHON 103 - #define MAX_VERSION_SIZE 4 typedef struct { @@ -457,6 +476,51 @@ return result; } +#if defined(SCRIPT_WRAPPER) +/* + * Check for a script located alongside the executable + */ + +#if defined(_WINDOWS) +#define SCRIPT_SUFFIX L"-script.pyw" +#else +#define SCRIPT_SUFFIX L"-script.py" +#endif + +static wchar_t wrapped_script_path[MAX_PATH]; + +/* Locate the script being wrapped. + * + * This code should store the name of the wrapped script in + * wrapped_script_path, or terminate the program with an error if there is no + * valid wrapped script file. + */ +static void +locate_wrapped_script() +{ + wchar_t * p; + size_t plen; + DWORD attrs; + + plen = GetModuleFileNameW(NULL, wrapped_script_path, MAX_PATH); + p = wcsrchr(wrapped_script_path, L'.'); + if (p == NULL) { + debug(L"GetModuleFileNameW returned value has no extension: %s\n", + wrapped_script_path); + error(RC_NO_SCRIPT, L"Wrapper name '%s' is not valid.", wrapped_script_path); + } + + wcsncpy_s(p, MAX_PATH - (p - wrapped_script_path) + 1, SCRIPT_SUFFIX, _TRUNCATE); + attrs = GetFileAttributesW(wrapped_script_path); + if (attrs == INVALID_FILE_ATTRIBUTES) { + debug(L"File '%s' non-existent\n", wrapped_script_path); + error(RC_NO_SCRIPT, L"Script file '%s' is not present.", wrapped_script_path); + } + + debug(L"Using wrapped script file '%s'\n", wrapped_script_path); +} +#endif + /* * Process creation code */ @@ -863,7 +927,7 @@ } BOM; /* - * Strictly, we don't need to handle UTF-16 anf UTF-32, since Python itself + * Strictly, we don't need to handle UTF-16 and UTF-32, since Python itself * doesn't. Never mind, one day it might - there's no harm leaving it in. */ static BOM BOMs[] = { @@ -1250,6 +1314,11 @@ VS_FIXEDFILEINFO * file_info; UINT block_size; int index; +#if defined(SCRIPT_WRAPPER) + int newlen; + wchar_t * newcommand; + wchar_t * av[2]; +#endif wp = get_env(L"PYLAUNCH_DEBUG"); if ((wp != NULL) && (*wp != L'\0')) @@ -1329,7 +1398,40 @@ } command = skip_me(GetCommandLineW()); - debug(L"Called with command line: %s", command); + debug(L"Called with command line: %s\n", command); + +#if defined(SCRIPT_WRAPPER) + /* The launcher is being used in "script wrapper" mode. + * There should therefore be a Python script named -script.py in + * the same directory as the launcher executable. + * Put the script name into argv as the first (script name) argument. + */ + + /* Get the wrapped script name - if the script is not present, this will + * terminate the program with an error. + */ + locate_wrapped_script(); + + /* Add the wrapped script to the start of command */ + newlen = wcslen(wrapped_script_path) + wcslen(command) + 2; /* ' ' + NUL */ + newcommand = malloc(sizeof(wchar_t) * newlen); + if (!newcommand) { + error(RC_NO_MEMORY, L"Could not allocate new command line"); + } + else { + wcscpy_s(newcommand, newlen, wrapped_script_path); + wcscat_s(newcommand, newlen, L" "); + wcscat_s(newcommand, newlen, command); + debug(L"Running wrapped script with command line '%s'\n", newcommand); + read_commands(); + av[0] = wrapped_script_path; + av[1] = NULL; + maybe_handle_shebang(av, newcommand); + /* Returns if no shebang line - pass to default processing */ + command = newcommand; + valid = FALSE; + } +#else if (argc <= 1) { valid = FALSE; p = NULL; @@ -1357,6 +1459,8 @@ } } } +#endif + if (!valid) { ip = locate_python(L""); if (ip == NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 14:22:13 2013 From: python-checkins at python.org (nick.coghlan) Date: Thu, 25 Jul 2013 14:22:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_PEP_394_based_on_pytho?= =?utf-8?q?n-dev_discussions?= Message-ID: <3c1CGs146jzSXZ@mail.python.org> http://hg.python.org/peps/rev/4b379a690ae2 changeset: 5007:4b379a690ae2 user: Nick Coghlan date: Thu Jul 25 22:21:27 2013 +1000 summary: Update PEP 394 based on python-dev discussions files: pep-0394.txt | 55 +++++++++++++++++++++++++++++---------- 1 files changed, 40 insertions(+), 15 deletions(-) diff --git a/pep-0394.txt b/pep-0394.txt --- a/pep-0394.txt +++ b/pep-0394.txt @@ -19,10 +19,17 @@ be portable across ``*nix`` systems, regardless of the default version of the Python interpreter (i.e. the version invoked by the ``python`` command). -* ``python2`` will refer to some version of Python 2.x -* ``python3`` will refer to some version of Python 3.x -* ``python`` *should* refer to the same target as ``python2`` but *may* - refer to ``python3`` on some bleeding edge distributions +* ``python2`` will refer to some version of Python 2.x. +* ``python3`` will refer to some version of Python 3.x. +* for the time being, all distributions *should* ensure that ``python`` + refers to the same target as ``python2``. +* however, end users should be aware that ``python`` refers to ``python3`` + on at least Arch Linux (that change is what prompted the creation of this + PEP), so ``python`` should be used in the shebang line only for scripts + that are source compatible with both Python 2 and 3. +* in preparation for an eventual change in the default version of Python, + Python 2 only scripts should either be updated to be source compatible + with Python 3 or else to use ``python2`` in the shebang line. Recommendation @@ -103,15 +110,29 @@ system. They will hopefully be helpful to any distributions considering making such a change. -* Distributions that only include ``python3`` in their base install (i.e. - they do not provide ``python2`` by default) along with those that are - aggressively trying to reach that point (and are willing to break third - party scripts while attempting to get there) are already beginning to alias - the ``python`` command to ``python3`` -* More conservative distributions that are less willing to tolerate breakage - of third party scripts continue to alias it to ``python2``. Until the - conventions described in this PEP are more widely adopted, having ``python`` - invoke ``python2`` will remain the recommended option. +* The main barrier to a distribution switching the ``python`` command from + ``python2`` to ``python3`` isn't breakage within the distribution, but + instead breakage of private third party scripts developed by sysadmins + and other users. Updating the ``python`` command to invoke ``python3`` + by default indicates that a distribution is willing to break such scripts + with errors that are potentially quite confusing for users that aren't + yet familiar with the backwards incompatible changes in Python 3. For + example, while the change of ``print`` from a statement to a builtin + function is relatively simple for automated converters to handle, the + SyntaxError from attempting to use the Python 2 notation in Python 3 is + thoroughly confusing if you aren't already aware of the change:: + + $ python3 -c 'print "Hello, world!"' + File "", line 1 + print "Hello, world!" + ^ + SyntaxError: invalid syntax + +* Avoiding breakage of such third party scripts is the key reason this + PEP recommends that ``python`` continue to refer to ``python2`` for the + time being. Until the conventions described in this PEP are more widely + adopted, having ``python`` invoke ``python2`` will remain the recommended + option. * The ``pythonX.X`` (e.g. ``python2.6``) commands exist on some systems, on which they invoke specific minor versions of the Python interpreter. It can be useful for distribution-specific packages to take advantage of these @@ -148,10 +169,13 @@ ``python`` command is only executed in an interactive manner as a user convenience, or to run scripts that are source compatible with both Python 2 and Python 3. +* one symbolic date being considered for a possible change to the official + recommendation in this PEP is the planned switch of Python 2.7 from full + maintenance to security update only status in 2015 (see PEP 373). Backwards Compatibility -========================= +======================= A potential problem can arise if a script adhering to the ``python2``/``python3`` convention is executed on a system not supporting @@ -217,7 +241,8 @@ This PEP deliberately excludes any proposals relating to Microsoft Windows, as devising an equivalent solution for Windows was deemed too complex to handle here. PEP 397 and the related discussion on the python-dev mailing list -address this issue. +address this issue (like this PEP, the PEP 397 launcher invokes Python 2 by +default if versions of both Python 2 and 3 are installed on the system). References -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jul 25 18:18:11 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 25 Jul 2013 18:18:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4NTAzOiBzbWFs?= =?utf-8?q?l_cleanups_in_test=5Femail=2E?= Message-ID: <3c1JW74TcRz7Ljm@mail.python.org> http://hg.python.org/cpython/rev/61d9c561b63d changeset: 84819:61d9c561b63d branch: 3.3 parent: 84816:b7ea3f94f6ca user: R David Murray date: Thu Jul 25 12:11:55 2013 -0400 summary: #18503: small cleanups in test_email. Patch by Vajrasky Kok. files: Lib/test/test_email/test_email.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -388,6 +388,7 @@ def test_del_param_on_nonexistent_header(self): msg = Message() + # Deleting param on empty msg should not raise exception. msg.del_param('filename', 'content-disposition') def test_del_nonexistent_param(self): @@ -395,7 +396,7 @@ msg.add_header('Content-Type', 'text/plain', charset='utf-8') existing_header = msg['Content-Type'] msg.del_param('foobar', header='Content-Type') - self.assertEqual(msg['Content-Type'], 'text/plain; charset="utf-8"') + self.assertEqual(msg['Content-Type'], existing_header) def test_set_type(self): eq = self.assertEqual @@ -2265,7 +2266,6 @@ eq(subpart['subject'], subject) def test_bad_multipart(self): - eq = self.assertEqual msg1 = Message() msg1['Subject'] = 'subpart 1' msg2 = Message() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 18:18:12 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 25 Jul 2013 18:18:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=2318503=3A_small_cleanups_in_test=5Femail=2E?= Message-ID: <3c1JW86sYQz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/be5f1f0bea09 changeset: 84820:be5f1f0bea09 parent: 84818:4123e002a1af parent: 84819:61d9c561b63d user: R David Murray date: Thu Jul 25 12:15:28 2013 -0400 summary: #18503: small cleanups in test_email. Patch by Vajrasky Kok. files: Lib/test/test_email/test_email.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -388,6 +388,7 @@ def test_del_param_on_nonexistent_header(self): msg = Message() + # Deleting param on empty msg should not raise exception. msg.del_param('filename', 'content-disposition') def test_del_nonexistent_param(self): @@ -395,7 +396,7 @@ msg.add_header('Content-Type', 'text/plain', charset='utf-8') existing_header = msg['Content-Type'] msg.del_param('foobar', header='Content-Type') - self.assertEqual(msg['Content-Type'], 'text/plain; charset="utf-8"') + self.assertEqual(msg['Content-Type'], existing_header) def test_set_type(self): eq = self.assertEqual @@ -2265,7 +2266,6 @@ eq(subpart['subject'], subject) def test_bad_multipart(self): - eq = self.assertEqual msg1 = Message() msg1['Subject'] = 'subpart 1' msg2 = Message() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 19:33:53 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 25 Jul 2013 19:33:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE1MTMwOiByZW1v?= =?utf-8?q?ve_repeat_of_abstract_paragraph_from_socket_howto_body=2E?= Message-ID: <3c1LBT23FHzRRV@mail.python.org> http://hg.python.org/cpython/rev/68fce7587f72 changeset: 84821:68fce7587f72 branch: 3.3 parent: 84819:61d9c561b63d user: R David Murray date: Thu Jul 25 13:24:15 2013 -0400 summary: #15130: remove repeat of abstract paragraph from socket howto body. Patch by Tshepang Lekhonkhobe. files: Doc/howto/sockets.rst | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -19,12 +19,6 @@ Sockets ======= -Sockets are used nearly everywhere, but are one of the most severely -misunderstood technologies around. This is a 10,000 foot overview of sockets. -It's not really a tutorial - you'll still have work to do in getting things -working. It doesn't cover the fine points (and there are a lot of them), but I -hope it will give you enough background to begin using them decently. - I'm only going to talk about INET (i.e. IPv4) sockets, but they account for at least 99% of the sockets in use. And I'll only talk about STREAM (i.e. TCP) sockets - unless you really know what you're doing (in which case this HOWTO isn't for you!), you'll get -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 19:33:54 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 25 Jul 2013 19:33:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2315130=3A_remove_repeat_of_abstract_paragraph_fr?= =?utf-8?q?om_socket_howto_body=2E?= Message-ID: <3c1LBV3wtvzS6G@mail.python.org> http://hg.python.org/cpython/rev/be4cc946b9df changeset: 84822:be4cc946b9df parent: 84820:be5f1f0bea09 parent: 84821:68fce7587f72 user: R David Murray date: Thu Jul 25 13:24:40 2013 -0400 summary: Merge #15130: remove repeat of abstract paragraph from socket howto body. files: Doc/howto/sockets.rst | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -19,12 +19,6 @@ Sockets ======= -Sockets are used nearly everywhere, but are one of the most severely -misunderstood technologies around. This is a 10,000 foot overview of sockets. -It's not really a tutorial - you'll still have work to do in getting things -working. It doesn't cover the fine points (and there are a lot of them), but I -hope it will give you enough background to begin using them decently. - I'm only going to talk about INET (i.e. IPv4) sockets, but they account for at least 99% of the sockets in use. And I'll only talk about STREAM (i.e. TCP) sockets - unless you really know what you're doing (in which case this HOWTO isn't for you!), you'll get -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 19:33:55 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 25 Jul 2013 19:33:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE1MTMwOiByZW1v?= =?utf-8?q?ve_repeat_of_abstract_paragraph_from_socket_howto_body=2E?= Message-ID: <3c1LBW6PvfzSqc@mail.python.org> http://hg.python.org/cpython/rev/a8d8bfb61874 changeset: 84823:a8d8bfb61874 branch: 2.7 parent: 84813:17542d36effd user: R David Murray date: Thu Jul 25 13:33:35 2013 -0400 summary: #15130: remove repeat of abstract paragraph from socket howto body. Patch by Tshepang Lekhonkhobe. files: Doc/howto/sockets.rst | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -19,12 +19,6 @@ Sockets ======= -Sockets are used nearly everywhere, but are one of the most severely -misunderstood technologies around. This is a 10,000 foot overview of sockets. -It's not really a tutorial - you'll still have work to do in getting things -working. It doesn't cover the fine points (and there are a lot of them), but I -hope it will give you enough background to begin using them decently. - I'm only going to talk about INET sockets, but they account for at least 99% of the sockets in use. And I'll only talk about STREAM sockets - unless you really know what you're doing (in which case this HOWTO isn't for you!), you'll get -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 20:55:49 2013 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 25 Jul 2013 20:55:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_typo_on_MutableSequenc?= =?utf-8?q?e_docstring=2E?= Message-ID: <3c1N1151pMzRMp@mail.python.org> http://hg.python.org/cpython/rev/fcb60a83858b changeset: 84824:fcb60a83858b parent: 84822:be4cc946b9df user: Guido van Rossum date: Thu Jul 25 11:55:41 2013 -0700 summary: Fix typo on MutableSequence docstring. files: Lib/collections/abc.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/collections/abc.py b/Lib/collections/abc.py --- a/Lib/collections/abc.py +++ b/Lib/collections/abc.py @@ -662,7 +662,7 @@ __slots__ = () - """All the operations on a read-only sequence. + """All the operations on a read-write sequence. Concrete subclasses must provide __new__ or __init__, __getitem__, __setitem__, __delitem__, __len__, and insert(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 22:12:23 2013 From: python-checkins at python.org (r.david.murray) Date: Thu, 25 Jul 2013 22:12:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2317818=3A_aifc=2Egetpara?= =?utf-8?q?ms_now_returns_a_namedtuple=2E?= Message-ID: <3c1PjM0CbbzRKx@mail.python.org> http://hg.python.org/cpython/rev/560c6e9d1beb changeset: 84825:560c6e9d1beb user: R David Murray date: Thu Jul 25 16:12:01 2013 -0400 summary: #17818: aifc.getparams now returns a namedtuple. Patch by Claudiu Popa. files: Doc/library/aifc.rst | 4 ++- Doc/whatsnew/3.4.rst | 6 +++++ Lib/aifc.py | 17 +++++++++----- Lib/test/test_aifc.py | 32 +++++++++++++++++++++++++++++ Lib/test/test_pyclbr.py | 2 +- Misc/NEWS | 2 + 6 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Doc/library/aifc.rst b/Doc/library/aifc.rst --- a/Doc/library/aifc.rst +++ b/Doc/library/aifc.rst @@ -96,7 +96,9 @@ .. method:: aifc.getparams() - Return a tuple consisting of all of the above values in the above order. + Returns a :func:`~collections.namedtuple` ``(nchannels, sampwidth, + framerate, nframes, comptype, compname)``, equivalent to output of the + :meth:`get\*` methods. .. method:: aifc.getmarkers() 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 @@ -173,6 +173,12 @@ FAIL_FAST`` (to parallel the similar option supported by the :mod:`unittest` CLI). (Contributed by R. David Murray in :issue:`11390`.) +aifc +---- + +The :meth:`~aifc.getparams` method now returns a namedtuple rather than a +plain tuple. (Contributed by Claudiu Popa in :issue:`17818`.) + functools --------- diff --git a/Lib/aifc.py b/Lib/aifc.py --- a/Lib/aifc.py +++ b/Lib/aifc.py @@ -69,7 +69,7 @@ getcomptype() -- returns compression type ('NONE' for AIFF files) getcompname() -- returns human-readable version of compression type ('not compressed' for AIFF files) - getparams() -- returns a tuple consisting of all of the + getparams() -- returns a namedtuple consisting of all of the above in the above order getmarkers() -- get the list of marks in the audio file or None if there are no marks @@ -252,6 +252,11 @@ _write_ulong(f, lomant) from chunk import Chunk +from collections import namedtuple + +_aifc_params = namedtuple('_aifc_params', + 'nchannels sampwidth framerate nframes comptype compname') + class Aifc_read: # Variables used in this class: @@ -378,9 +383,9 @@ ## return self._version def getparams(self): - return self.getnchannels(), self.getsampwidth(), \ - self.getframerate(), self.getnframes(), \ - self.getcomptype(), self.getcompname() + return _aifc_params(self.getnchannels(), self.getsampwidth(), + self.getframerate(), self.getnframes(), + self.getcomptype(), self.getcompname()) def getmarkers(self): if len(self._markers) == 0: @@ -658,8 +663,8 @@ def getparams(self): if not self._nchannels or not self._sampwidth or not self._framerate: raise Error('not all parameters set') - return self._nchannels, self._sampwidth, self._framerate, \ - self._nframes, self._comptype, self._compname + return _aifc_params(self._nchannels, self._sampwidth, self._framerate, + self._nframes, self._comptype, self._compname) def setmark(self, id, pos, name): if id <= 0: diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -3,6 +3,7 @@ import os import io import struct +import pickle import aifc @@ -31,6 +32,7 @@ def test_params(self): f = self.f = aifc.open(self.sndfilepath) + params = f.getparams() self.assertEqual(f.getfp().name, self.sndfilepath) self.assertEqual(f.getnchannels(), 2) self.assertEqual(f.getsampwidth(), 2) @@ -43,6 +45,36 @@ (2, 2, 48000, 14400, b'NONE', b'not compressed'), ) + params = f.getparams() + self.assertEqual(params.nchannels, 2) + self.assertEqual(params.sampwidth, 2) + self.assertEqual(params.framerate, 48000) + self.assertEqual(params.nframes, 14400) + self.assertEqual(params.comptype, b'NONE') + self.assertEqual(params.compname, b'not compressed') + + def test_params_added(self): + f = self.f = aifc.open(TESTFN, 'wb') + f.aiff() + f.setparams((1, 1, 1, 1, b'NONE', b'')) + f.close() + + f = self.f = aifc.open(TESTFN, 'rb') + params = f.getparams() + self.assertEqual(params.nchannels, f.getnchannels()) + self.assertEqual(params.sampwidth, f.getsampwidth()) + self.assertEqual(params.framerate, f.getframerate()) + self.assertEqual(params.nframes, f.getnframes()) + self.assertEqual(params.comptype, f.getcomptype()) + self.assertEqual(params.compname, f.getcompname()) + + def test_getparams_picklable(self): + self.f = aifc.open(self.sndfilepath) + params = self.f.getparams() + dump = pickle.dumps(params) + self.assertEqual(pickle.loads(dump), params) + self.f.close() + def test_context_manager(self): with open(self.sndfilepath, 'rb') as testfile: with aifc.open(testfile) as f: diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -158,7 +158,7 @@ cm('random', ignore=('Random',)) # from _random import Random as CoreGenerator cm('cgi', ignore=('log',)) # set with = in module cm('pickle') - cm('aifc', ignore=('openfp',)) # set with = in module + cm('aifc', ignore=('openfp', '_aifc_params')) # set with = in module cm('sre_parse', ignore=('dump',)) # from sre_constants import * cm('pdb') cm('pydoc') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -166,6 +166,8 @@ Library ------- +- Issue #17818: aifc.getparams now returns a namedtuple. + - Issue #18549: Eliminate dead code in socket_ntohl() - Issue #18530: Remove additional stat call from posixpath.ismount. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 22:51:11 2013 From: python-checkins at python.org (ethan.furman) Date: Thu, 25 Jul 2013 22:51:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2318545=3A_now_only?= =?utf-8?q?_executes_member=5Ftype_if_no_=5Fvalue=5F_is_assigned_in?= Message-ID: <3c1QZ74tLCzSFM@mail.python.org> http://hg.python.org/cpython/rev/95e1d0efd896 changeset: 84826:95e1d0efd896 user: Ethan Furman date: Thu Jul 25 13:50:45 2013 -0700 summary: Close #18545: now only executes member_type if no _value_ is assigned in __new__. files: Lib/enum.py | 8 ++++---- Lib/test/test_enum.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Lib/enum.py b/Lib/enum.py --- a/Lib/enum.py +++ b/Lib/enum.py @@ -152,12 +152,12 @@ args = (args, ) # wrap it one more time if not use_args: enum_member = __new__(enum_class) - original_value = value + if not hasattr(enum_member, '_value_'): + enum_member._value_ = value else: enum_member = __new__(enum_class, *args) - original_value = member_type(*args) - if not hasattr(enum_member, '_value_'): - enum_member._value_ = original_value + if not hasattr(enum_member, '_value_'): + enum_member._value_ = member_type(*args) value = enum_member._value_ enum_member._member_type_ = member_type enum_member._name_ = member_name diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -934,6 +934,22 @@ self.assertEqual(ColorInAList.red.value, [1]) self.assertEqual(ColorInAList([1]), ColorInAList.red) + def test_conflicting_types_resolved_in_new(self): + class LabelledIntEnum(int, Enum): + def __new__(cls, *args): + value, label = args + obj = int.__new__(cls, value) + obj.label = label + obj._value_ = value + return obj + + class LabelledList(LabelledIntEnum): + unprocessed = (1, "Unprocessed") + payment_complete = (2, "Payment Complete") + + self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete]) + self.assertEqual(LabelledList.unprocessed, 1) + self.assertEqual(LabelledList(1), LabelledList.unprocessed) class TestUnique(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 23:36:40 2013 From: python-checkins at python.org (brett.cannon) Date: Thu, 25 Jul 2013 23:36:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTU2?= =?utf-8?q?=3A_Check_the_return_value_for_PyUnicode=5FAsWideChar=28=29_in?= Message-ID: <3c1RZc5WkRzSRg@mail.python.org> http://hg.python.org/cpython/rev/78e8980ec9f7 changeset: 84827:78e8980ec9f7 branch: 3.3 parent: 84821:68fce7587f72 user: Brett Cannon date: Thu Jul 25 17:34:00 2013 -0400 summary: Issue #18556: Check the return value for PyUnicode_AsWideChar() in U_set() from ctypes. CID #486657 files: Misc/NEWS | 3 +++ Modules/_ctypes/cfield.c | 6 +++++- 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,9 @@ Library ------- +- Issue #18556: Check the return value of a PyUnicode_AsWideChar() call in + ctypes' U_set(). + - Issue #18549: Eliminate dead code in socket_ntohl() - Issue #18514: Fix unreachable Py_DECREF() call in PyCData_FromBaseObj() diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -1260,7 +1260,11 @@ } else if (size < length-1) /* copy terminating NUL character if there is space */ size += 1; - PyUnicode_AsWideChar(value, (wchar_t *)ptr, size); + + if (PyUnicode_AsWideChar(value, (wchar_t *)ptr, size) == -1) { + return NULL; + } + return value; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 25 23:36:42 2013 From: python-checkins at python.org (brett.cannon) Date: Thu, 25 Jul 2013 23:36:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_for_issue_=2318556?= Message-ID: <3c1RZf0Mgcz7LjN@mail.python.org> http://hg.python.org/cpython/rev/2f4c4db9aee5 changeset: 84828:2f4c4db9aee5 parent: 84826:95e1d0efd896 parent: 84827:78e8980ec9f7 user: Brett Cannon date: Thu Jul 25 17:36:15 2013 -0400 summary: merge for issue #18556 files: Misc/NEWS | 3 +++ Modules/_ctypes/cfield.c | 6 +++++- 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -166,6 +166,9 @@ Library ------- +- Issue #18556: Check the return type of PyUnicode_AsWideChar() in ctype's + U_set(). + - Issue #17818: aifc.getparams now returns a namedtuple. - Issue #18549: Eliminate dead code in socket_ntohl() diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -1260,7 +1260,11 @@ } else if (size < length-1) /* copy terminating NUL character if there is space */ size += 1; - PyUnicode_AsWideChar(value, (wchar_t *)ptr, size); + + if (PyUnicode_AsWideChar(value, (wchar_t *)ptr, size) == -1) { + return NULL; + } + return value; } -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 26 05:53:07 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 26 Jul 2013 05:53:07 +0200 Subject: [Python-checkins] Daily reference leaks (2f4c4db9aee5): sum=0 Message-ID: results for 2f4c4db9aee5 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloggHppxB', '-x'] From python-checkins at python.org Fri Jul 26 14:46:17 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 14:46:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_possible_N?= =?utf-8?q?ULL_pointer_dereference_in_PyCurses=5FStart=5FColor=28=29?= Message-ID: <3c1qm9306hz7LjM@mail.python.org> http://hg.python.org/cpython/rev/aedcf7ef8489 changeset: 84829:aedcf7ef8489 branch: 3.3 parent: 84827:78e8980ec9f7 user: Christian Heimes date: Fri Jul 26 14:45:37 2013 +0200 summary: Fix possible NULL pointer dereference in PyCurses_Start_Color() CID 1058276 files: Modules/_cursesmodule.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2930,9 +2930,13 @@ if (code != ERR) { initialisedcolors = TRUE; c = PyLong_FromLong((long) COLORS); + if (c == NULL) + return NULL; PyDict_SetItemString(ModDict, "COLORS", c); Py_DECREF(c); cp = PyLong_FromLong((long) COLOR_PAIRS); + if (cp == NULL) + return NULL; PyDict_SetItemString(ModDict, "COLOR_PAIRS", cp); Py_DECREF(cp); Py_INCREF(Py_None); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 14:46:18 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 14:46:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_possible_NULL_pointer_dereference_in_PyCurses=5FStar?= =?utf-8?b?dF9Db2xvcigp?= Message-ID: <3c1qmB52L3z7Lk3@mail.python.org> http://hg.python.org/cpython/rev/3c5bf0c7a290 changeset: 84830:3c5bf0c7a290 parent: 84828:2f4c4db9aee5 parent: 84829:aedcf7ef8489 user: Christian Heimes date: Fri Jul 26 14:46:02 2013 +0200 summary: Fix possible NULL pointer dereference in PyCurses_Start_Color() CID 1058276 files: Modules/_cursesmodule.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2926,9 +2926,13 @@ if (code != ERR) { initialisedcolors = TRUE; c = PyLong_FromLong((long) COLORS); + if (c == NULL) + return NULL; PyDict_SetItemString(ModDict, "COLORS", c); Py_DECREF(c); cp = PyLong_FromLong((long) COLOR_PAIRS); + if (cp == NULL) + return NULL; PyDict_SetItemString(ModDict, "COLOR_PAIRS", cp); Py_DECREF(cp); Py_INCREF(Py_None); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 14:52:36 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 14:52:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_possible_N?= =?utf-8?q?ULL_pointer_dereferences_in_testcapi_module?= Message-ID: <3c1qvS09PVz7LjM@mail.python.org> http://hg.python.org/cpython/rev/d49f65ff4f3c changeset: 84831:d49f65ff4f3c branch: 3.3 parent: 84829:aedcf7ef8489 user: Christian Heimes date: Fri Jul 26 14:52:18 2013 +0200 summary: Fix possible NULL pointer dereferences in testcapi module CID 1058280 CID 1058282 CID 1058284 files: Modules/_testcapimodule.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -120,6 +120,10 @@ for (i = 0; i < count; i++) { v = PyLong_FromLong(i); + if (v == NULL) { + Py_DECREF(v); + return -1; + } if (PyDict_SetItem(dict, v, v) < 0) { Py_DECREF(v); return -1; @@ -1642,6 +1646,8 @@ for (i = 0; i < Py_ARRAY_LENGTH(testcases); ++i) { PyObject *plong = PyLong_FromLong(testcases[i].input); + if (plong == NULL) + return NULL; size_t nbits = _PyLong_NumBits(plong); int sign = _PyLong_Sign(plong); @@ -2234,7 +2240,7 @@ gettimeofday(&start, NULL); for(i=0; i < 10000000; i++) { result = PyNumber_Add(op1, op1); - Py_DECREF(result); + Py_XDECREF(result); } gettimeofday(&stop, NULL); Py_DECREF(op1); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 14:52:37 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 14:52:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_possible_NULL_pointer_dereferences_in_testcapi_modul?= =?utf-8?q?e?= Message-ID: <3c1qvT2BBKz7LjW@mail.python.org> http://hg.python.org/cpython/rev/33891989c9cf changeset: 84832:33891989c9cf parent: 84830:3c5bf0c7a290 parent: 84831:d49f65ff4f3c user: Christian Heimes date: Fri Jul 26 14:52:26 2013 +0200 summary: Fix possible NULL pointer dereferences in testcapi module CID 1058280 CID 1058282 CID 1058284 files: Modules/_testcapimodule.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -120,6 +120,10 @@ for (i = 0; i < count; i++) { v = PyLong_FromLong(i); + if (v == NULL) { + Py_DECREF(v); + return -1; + } if (PyDict_SetItem(dict, v, v) < 0) { Py_DECREF(v); return -1; @@ -1656,6 +1660,8 @@ for (i = 0; i < Py_ARRAY_LENGTH(testcases); ++i) { PyObject *plong = PyLong_FromLong(testcases[i].input); + if (plong == NULL) + return NULL; size_t nbits = _PyLong_NumBits(plong); int sign = _PyLong_Sign(plong); @@ -2248,7 +2254,7 @@ gettimeofday(&start, NULL); for(i=0; i < 10000000; i++) { result = PyNumber_Add(op1, op1); - Py_DECREF(result); + Py_XDECREF(result); } gettimeofday(&stop, NULL); Py_DECREF(op1); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 15:07:47 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 15:07:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_memory_lea?= =?utf-8?q?ks_and_add_checks_for_failing_malloc=28=29_calls_to_testcapi_mo?= =?utf-8?q?dule?= Message-ID: <3c1rDz5tf7z7Lkv@mail.python.org> http://hg.python.org/cpython/rev/081e9fa5e933 changeset: 84833:081e9fa5e933 branch: 3.3 parent: 84831:d49f65ff4f3c user: Christian Heimes date: Fri Jul 26 15:03:50 2013 +0200 summary: Fix memory leaks and add checks for failing malloc() calls to testcapi module CID 1058288 files: Modules/_testcapimodule.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2183,6 +2183,8 @@ /* Test 3: Allocate a few integers, then release them all simultaneously. */ multiple = malloc(sizeof(PyObject*) * 1000); + if (multiple == NULL) + return PyErr_NoMemory(); gettimeofday(&start, NULL); for(k=0; k < 20000; k++) { for(i=0; i < 1000; i++) { @@ -2194,10 +2196,13 @@ } gettimeofday(&stop, NULL); print_delta(3, &start, &stop); + free(multiple); /* Test 4: Allocate many integers, then release them all simultaneously. */ multiple = malloc(sizeof(PyObject*) * 1000000); + if (multiple == NULL) + return PyErr_NoMemory(); gettimeofday(&start, NULL); for(k=0; k < 20; k++) { for(i=0; i < 1000000; i++) { @@ -2209,9 +2214,12 @@ } gettimeofday(&stop, NULL); print_delta(4, &start, &stop); + free(multiple); /* Test 5: Allocate many integers < 32000 */ multiple = malloc(sizeof(PyObject*) * 1000000); + if (multiple == NULL) + return PyErr_NoMemory(); gettimeofday(&start, NULL); for(k=0; k < 10; k++) { for(i=0; i < 1000000; i++) { @@ -2223,6 +2231,7 @@ } gettimeofday(&stop, NULL); print_delta(5, &start, &stop); + free(multiple); /* Test 6: Perform small int addition */ op1 = PyLong_FromLong(1); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 15:07:49 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 15:07:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_declaratio?= =?utf-8?q?n-after-statement_of_d49f65ff4f3c?= Message-ID: <3c1rF10Z4mz7Ll0@mail.python.org> http://hg.python.org/cpython/rev/708811f8470f changeset: 84834:708811f8470f branch: 3.3 user: Christian Heimes date: Fri Jul 26 15:06:48 2013 +0200 summary: Fix declaration-after-statement of d49f65ff4f3c files: Modules/_testcapimodule.c | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1645,11 +1645,15 @@ int i; for (i = 0; i < Py_ARRAY_LENGTH(testcases); ++i) { - PyObject *plong = PyLong_FromLong(testcases[i].input); + size_t nbits; + int sign; + PyObject *plong; + + plong = PyLong_FromLong(testcases[i].input); if (plong == NULL) return NULL; - size_t nbits = _PyLong_NumBits(plong); - int sign = _PyLong_Sign(plong); + nbits = _PyLong_NumBits(plong); + sign = _PyLong_Sign(plong); Py_DECREF(plong); if (nbits != testcases[i].nbits) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 15:07:50 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 15:07:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_memory_leaks_and_add_checks_for_failing_malloc=28=29?= =?utf-8?q?_calls_to_testcapi_module?= Message-ID: <3c1rF22jkSz7Ll5@mail.python.org> http://hg.python.org/cpython/rev/f82fe2b43165 changeset: 84835:f82fe2b43165 parent: 84832:33891989c9cf parent: 84834:708811f8470f user: Christian Heimes date: Fri Jul 26 15:07:34 2013 +0200 summary: Fix memory leaks and add checks for failing malloc() calls to testcapi module CID 1058288 Fix declaration-after-statement of d49f65ff4f3c files: Modules/_testcapimodule.c | 19 ++++++++++++++++--- 1 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1659,11 +1659,15 @@ int i; for (i = 0; i < Py_ARRAY_LENGTH(testcases); ++i) { - PyObject *plong = PyLong_FromLong(testcases[i].input); + size_t nbits; + int sign; + PyObject *plong; + + plong = PyLong_FromLong(testcases[i].input); if (plong == NULL) return NULL; - size_t nbits = _PyLong_NumBits(plong); - int sign = _PyLong_Sign(plong); + nbits = _PyLong_NumBits(plong); + sign = _PyLong_Sign(plong); Py_DECREF(plong); if (nbits != testcases[i].nbits) @@ -2197,6 +2201,8 @@ /* Test 3: Allocate a few integers, then release them all simultaneously. */ multiple = malloc(sizeof(PyObject*) * 1000); + if (multiple == NULL) + return PyErr_NoMemory(); gettimeofday(&start, NULL); for(k=0; k < 20000; k++) { for(i=0; i < 1000; i++) { @@ -2208,10 +2214,13 @@ } gettimeofday(&stop, NULL); print_delta(3, &start, &stop); + free(multiple); /* Test 4: Allocate many integers, then release them all simultaneously. */ multiple = malloc(sizeof(PyObject*) * 1000000); + if (multiple == NULL) + return PyErr_NoMemory(); gettimeofday(&start, NULL); for(k=0; k < 20; k++) { for(i=0; i < 1000000; i++) { @@ -2223,9 +2232,12 @@ } gettimeofday(&stop, NULL); print_delta(4, &start, &stop); + free(multiple); /* Test 5: Allocate many integers < 32000 */ multiple = malloc(sizeof(PyObject*) * 1000000); + if (multiple == NULL) + return PyErr_NoMemory(); gettimeofday(&start, NULL); for(k=0; k < 10; k++) { for(i=0; i < 1000000; i++) { @@ -2237,6 +2249,7 @@ } gettimeofday(&stop, NULL); print_delta(5, &start, &stop); + free(multiple); /* Test 6: Perform small int addition */ op1 = PyLong_FromLong(1); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 15:26:36 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 15:26:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_remove_surplus?= =?utf-8?q?_and_wrong_Py=5FDECREF=28=29_introduced_in_33891989c9cf?= Message-ID: <3c1rfh4zWpz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/e6e9e237cc6b changeset: 84836:e6e9e237cc6b branch: 3.3 parent: 84834:708811f8470f user: Christian Heimes date: Fri Jul 26 15:26:18 2013 +0200 summary: remove surplus and wrong Py_DECREF() introduced in 33891989c9cf files: Modules/_testcapimodule.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -121,7 +121,6 @@ for (i = 0; i < count; i++) { v = PyLong_FromLong(i); if (v == NULL) { - Py_DECREF(v); return -1; } if (PyDict_SetItem(dict, v, v) < 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 15:26:37 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 15:26:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_remove_surplus_and_wrong_Py=5FDECREF=28=29_introduced_in?= =?utf-8?q?_33891989c9cf?= Message-ID: <3c1rfj6zslz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/ad866139a059 changeset: 84837:ad866139a059 parent: 84835:f82fe2b43165 parent: 84836:e6e9e237cc6b user: Christian Heimes date: Fri Jul 26 15:26:26 2013 +0200 summary: remove surplus and wrong Py_DECREF() introduced in 33891989c9cf files: Modules/_testcapimodule.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -121,7 +121,6 @@ for (i = 0; i < count; i++) { v = PyLong_FromLong(i); if (v == NULL) { - Py_DECREF(v); return -1; } if (PyDict_SetItem(dict, v, v) < 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 15:51:42 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 15:51:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Check_return_v?= =?utf-8?q?alue_of_PyLong=5FFromLong=28X509=5Fget=5Fversion=28=29=29=2E_It?= =?utf-8?q?_might_be_NULL_if?= Message-ID: <3c1sCf1LMFz7LjM@mail.python.org> http://hg.python.org/cpython/rev/7d6781ec35ea changeset: 84838:7d6781ec35ea branch: 3.3 parent: 84836:e6e9e237cc6b user: Christian Heimes date: Fri Jul 26 15:51:18 2013 +0200 summary: Check return value of PyLong_FromLong(X509_get_version()). It might be NULL if X509_get_version() grows beyond our small int cache. CID 1058279 files: Modules/_ssl.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -903,6 +903,8 @@ Py_DECREF(issuer); version = PyLong_FromLong(X509_get_version(certificate) + 1); + if (version == NULL) + goto fail0; if (PyDict_SetItemString(retval, "version", version) < 0) { Py_DECREF(version); goto fail0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 15:51:43 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 15:51:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Check_return_value_of_PyLong=5FFromLong=28X509=5Fget=5Fv?= =?utf-8?q?ersion=28=29=29=2E_It_might_be_NULL_if?= Message-ID: <3c1sCg3JP0z7LjM@mail.python.org> http://hg.python.org/cpython/rev/8438a75114e1 changeset: 84839:8438a75114e1 parent: 84837:ad866139a059 parent: 84838:7d6781ec35ea user: Christian Heimes date: Fri Jul 26 15:51:35 2013 +0200 summary: Check return value of PyLong_FromLong(X509_get_version()). It might be NULL if X509_get_version() grows beyond our small int cache. CID 1058279 files: Modules/_ssl.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -937,6 +937,8 @@ Py_DECREF(issuer); version = PyLong_FromLong(X509_get_version(certificate) + 1); + if (version == NULL) + goto fail0; if (PyDict_SetItemString(retval, "version", version) < 0) { Py_DECREF(version); goto fail0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 15:54:24 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 15:54:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Handle_yet_ano?= =?utf-8?q?ther_potential_failure_in_testcapi?= Message-ID: <3c1sGm3Kbjz7LkV@mail.python.org> http://hg.python.org/cpython/rev/32ebd1846d07 changeset: 84840:32ebd1846d07 branch: 3.3 parent: 84838:7d6781ec35ea user: Christian Heimes date: Fri Jul 26 15:54:07 2013 +0200 summary: Handle yet another potential failure in testcapi CID 1058280 files: Modules/_testcapimodule.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2249,6 +2249,8 @@ /* Test 7: Perform medium int addition */ op1 = PyLong_FromLong(1000); + if (op1 == NULL) + return NULL; gettimeofday(&start, NULL); for(i=0; i < 10000000; i++) { result = PyNumber_Add(op1, op1); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 15:54:25 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 15:54:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Handle_yet_another_potential_failure_in_testcapi?= Message-ID: <3c1sGn5CPTz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/40bec72df2a1 changeset: 84841:40bec72df2a1 parent: 84839:8438a75114e1 parent: 84840:32ebd1846d07 user: Christian Heimes date: Fri Jul 26 15:54:13 2013 +0200 summary: Handle yet another potential failure in testcapi CID 1058280 files: Modules/_testcapimodule.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2263,6 +2263,8 @@ /* Test 7: Perform medium int addition */ op1 = PyLong_FromLong(1000); + if (op1 == NULL) + return NULL; gettimeofday(&start, NULL); for(i=0; i < 10000000; i++) { result = PyNumber_Add(op1, op1); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 18:00:22 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 18:00:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Coverity=3A_model_PyLong?= =?utf-8?q?=5FFrom*=28=29_functions?= Message-ID: <3c1w464pW7z7Lkv@mail.python.org> http://hg.python.org/cpython/rev/7e69961d82b2 changeset: 84842:7e69961d82b2 user: Christian Heimes date: Fri Jul 26 18:00:12 2013 +0200 summary: Coverity: model PyLong_From*() functions files: Misc/coverity_model.c | 35 ++++++++++++++++++++++++++---- 1 files changed, 30 insertions(+), 5 deletions(-) diff --git a/Misc/coverity_model.c b/Misc/coverity_model.c --- a/Misc/coverity_model.c +++ b/Misc/coverity_model.c @@ -19,8 +19,10 @@ /* dummy definitions, in most cases struct fields aren't required. */ #define NULL (void *)0 +#define assert(op) /* empty */ typedef int sdigit; typedef long Py_ssize_t; +typedef long long PY_LONG_LONG; typedef unsigned short wchar_t; typedef struct {} PyObject; typedef struct {} grammar; @@ -37,15 +39,38 @@ /* Objects/longobject.c * NEGATIVE_RETURNS false positive */ -static PyObject small_ints[257 + 5]; - static PyObject *get_small_int(sdigit ival) { + /* Never returns NULL */ PyObject *p; - if (((ival + 5) >= 0) && ((ival + 5) < 257 + 5)) { - return &small_ints[ival + 5]; + assert(p != NULL); + return p; +} + +PyObject *PyLong_FromLong(long ival) +{ + PyObject *p; + int maybe; + + if ((ival >= -5) && (ival < 257 + 5)) { + p = get_small_int(ival); + assert(p != NULL); + return p; } - return p; + if (maybe) + return p; + else + return NULL; +} + +PyObject *PyLong_FromLongLong(PY_LONG_LONG ival) +{ + return PyLong_FromLong((long)ival); +} + +PyObject *PyLong_FromSsize_t(Py_ssize_t ival) +{ + return PyLong_FromLong((long)ival); } /* tainted sinks -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 18:34:17 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 18:34:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Document_special_case_of_?= =?utf-8?b?UHlMb25nX0Zyb21Mb25nKCkgZm9yIG4gWy01IC4uLiArMjU1XQ==?= Message-ID: <3c1wqF1l4mz7LjN@mail.python.org> http://hg.python.org/devguide/rev/b36dc969c0d2 changeset: 632:b36dc969c0d2 user: Christian Heimes date: Fri Jul 26 18:34:09 2013 +0200 summary: Document special case of PyLong_FromLong() for n [-5 ... +255] files: coverity.rst | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/coverity.rst b/coverity.rst --- a/coverity.rst +++ b/coverity.rst @@ -57,11 +57,15 @@ without touching its reference count. On this ground the analyzer detects a resource leak. CID 719685 -``PyLong_FromLong(-1)`` +``PyLong_FromLong()`` for negative values Coverity claims that ``PyLong_FromLong()`` and other ``PyLong_From*()`` functions cannot handle a negative value because the value might be used as an array index in ``get_small_int()``. CID 486783 +``PyLong_FromLong()`` for n in [-5 ... +255] + For integers in the range of Python's small int cache the ``PyLong_From*()`` + function can never fail and never returns NULL. CID 1058291 + ``PyArg_ParseTupleAndKeywords(args, kwargs, "s#", &data, &length)`` Some functions use the format char combination such as ``s#``, ``u#`` or ``z#`` to get data and length of a character array. Coverity doesn't -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jul 26 22:24:01 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 26 Jul 2013 22:24:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318519=3A_the_Pyth?= =?utf-8?q?on_authorizer_callback_of_sqlite3_must_not_raise_Python?= Message-ID: <3c21wK0NhbzRW2@mail.python.org> http://hg.python.org/cpython/rev/f7a0a4e0ada4 changeset: 84843:f7a0a4e0ada4 user: Victor Stinner date: Fri Jul 26 22:23:33 2013 +0200 summary: Issue #18519: the Python authorizer callback of sqlite3 must not raise Python exceptions The exception is printed if sqlite3.enable_callback_tracebacks(True) has been called, otherwise the exception is cleared. files: Modules/_sqlite/connection.c | 41 +++++++++++------------ 1 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -884,32 +884,31 @@ gilstate = PyGILState_Ensure(); #endif - if (!PyErr_Occurred()) { - ret = PyObject_CallFunction((PyObject*)user_arg, "issss", action, arg1, arg2, dbname, access_attempt_source); + ret = PyObject_CallFunction((PyObject*)user_arg, "issss", action, arg1, arg2, dbname, access_attempt_source); - if (!ret) { - if (_enable_callback_tracebacks) { - PyErr_Print(); - } else { - PyErr_Clear(); - } + if (ret == NULL) { + if (_enable_callback_tracebacks) + PyErr_Print(); + else + PyErr_Clear(); - rc = SQLITE_DENY; - } else { - if (PyLong_Check(ret)) { - rc = _PyLong_AsInt(ret); - if (rc == -1 && PyErr_Occurred()) - rc = SQLITE_DENY; - } else { + rc = SQLITE_DENY; + } + else { + if (PyLong_Check(ret)) { + rc = _PyLong_AsInt(ret); + if (rc == -1 && PyErr_Occurred()) { + if (_enable_callback_tracebacks) + PyErr_Print(); + else + PyErr_Clear(); rc = SQLITE_DENY; } - Py_DECREF(ret); } - } - else { - /* A previous call to the authorizer callback failed and raised an - exception: don't call the Python authorizer callback */ - rc = SQLITE_DENY; + else { + rc = SQLITE_DENY; + } + Py_DECREF(ret); } #ifdef WITH_THREAD -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 22:45:57 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 22:45:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTU5?= =?utf-8?q?=3A_Fix_NULL_pointer_dereference_error_in_=5Fpickle_module?= Message-ID: <3c22Pd5rj5z7Ljh@mail.python.org> http://hg.python.org/cpython/rev/dbdd07657e23 changeset: 84844:dbdd07657e23 branch: 3.3 parent: 84840:32ebd1846d07 user: Christian Heimes date: Fri Jul 26 22:45:00 2013 +0200 summary: Issue #18559: Fix NULL pointer dereference error in _pickle module files: Misc/NEWS | 2 ++ Modules/_pickle.c | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,8 @@ Library ------- +- Issue #18559: Fix NULL pointer dereference error in _pickle module + - Issue #18556: Check the return value of a PyUnicode_AsWideChar() call in ctypes' U_set(). diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4816,9 +4816,10 @@ value = _Unpickler_MemoGet(self, idx); if (value == NULL) { PyObject *key = PyLong_FromSsize_t(idx); - if (!PyErr_Occurred()) + if (key != NULL) { PyErr_SetObject(PyExc_KeyError, key); - Py_DECREF(key); + Py_DECREF(key); + } return -1; } @@ -4841,9 +4842,10 @@ value = _Unpickler_MemoGet(self, idx); if (value == NULL) { PyObject *key = PyLong_FromSsize_t(idx); - if (!PyErr_Occurred()) + if (key != NULL) { PyErr_SetObject(PyExc_KeyError, key); - Py_DECREF(key); + Py_DECREF(key); + } return -1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 22:45:59 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 22:45:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318559=3A_Fix_NULL_pointer_dereference_error_in_?= =?utf-8?q?=5Fpickle_module?= Message-ID: <3c22Pg0tRYz7Lk2@mail.python.org> http://hg.python.org/cpython/rev/b33f81974516 changeset: 84845:b33f81974516 parent: 84843:f7a0a4e0ada4 parent: 84844:dbdd07657e23 user: Christian Heimes date: Fri Jul 26 22:45:47 2013 +0200 summary: Issue #18559: Fix NULL pointer dereference error in _pickle module files: Misc/NEWS | 2 ++ Modules/_pickle.c | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -166,6 +166,8 @@ Library ------- +- Issue #18559: Fix NULL pointer dereference error in _pickle module + - Issue #18556: Check the return type of PyUnicode_AsWideChar() in ctype's U_set(). diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4836,9 +4836,10 @@ value = _Unpickler_MemoGet(self, idx); if (value == NULL) { PyObject *key = PyLong_FromSsize_t(idx); - if (!PyErr_Occurred()) + if (key != NULL) { PyErr_SetObject(PyExc_KeyError, key); - Py_DECREF(key); + Py_DECREF(key); + } return -1; } @@ -4861,9 +4862,10 @@ value = _Unpickler_MemoGet(self, idx); if (value == NULL) { PyObject *key = PyLong_FromSsize_t(idx); - if (!PyErr_Occurred()) + if (key != NULL) { PyErr_SetObject(PyExc_KeyError, key); - Py_DECREF(key); + Py_DECREF(key); + } return -1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 22:50:11 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 22:50:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTYw?= =?utf-8?q?=3A_Fix_potential_NULL_pointer_dereference_in_sum=28=29?= Message-ID: <3c22VW4T4Rz7LjT@mail.python.org> http://hg.python.org/cpython/rev/de7e4fd634fb changeset: 84846:de7e4fd634fb branch: 3.3 parent: 84844:dbdd07657e23 user: Christian Heimes date: Fri Jul 26 22:49:26 2013 +0200 summary: Issue #18560: Fix potential NULL pointer dereference in sum() files: Misc/NEWS | 2 ++ Python/bltinmodule.c | 5 +++++ 2 files changed, 7 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 #18560: Fix potential NULL pointer dereference in sum(). + - Issue #15905: Fix theoretical buffer overflow in handling of sys.argv[0], prefix and exec_prefix if the operation system does not obey MAXPATHLEN. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2009,6 +2009,11 @@ } /* Either overflowed or is not an int. Restore real objects and process normally */ result = PyLong_FromLong(i_result); + if (result == NULL) { + Py_DECREF(item); + Py_DECREF(iter); + return NULL; + } temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 22:50:12 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 22:50:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318560=3A_Fix_potential_NULL_pointer_dereference?= =?utf-8?b?IGluIHN1bSgp?= Message-ID: <3c22VX6bRsz7LjX@mail.python.org> http://hg.python.org/cpython/rev/a5d9e2f3f6c7 changeset: 84847:a5d9e2f3f6c7 parent: 84845:b33f81974516 parent: 84846:de7e4fd634fb user: Christian Heimes date: Fri Jul 26 22:50:01 2013 +0200 summary: Issue #18560: Fix potential NULL pointer dereference in sum() files: Misc/NEWS | 2 ++ Python/bltinmodule.c | 5 +++++ 2 files changed, 7 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 #18560: Fix potential NULL pointer dereference in sum(). + - Issue #18520: Add a new PyStructSequence_InitType2() function, same than PyStructSequence_InitType() except that it has a return value (0 on success, -1 on error). diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2030,6 +2030,11 @@ } /* Either overflowed or is not an int. Restore real objects and process normally */ result = PyLong_FromLong(i_result); + if (result == NULL) { + Py_DECREF(item); + Py_DECREF(iter); + return NULL; + } temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 23:04:51 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 23:04:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTYx?= =?utf-8?q?=3A_Skip_name_in_ctypes=27_=5Fbuild=5Fcallargs=28=29_if_name_is?= =?utf-8?q?_NULL=2E?= Message-ID: <3c22qR6WSvzQQ2@mail.python.org> http://hg.python.org/cpython/rev/57457028dd7a changeset: 84848:57457028dd7a branch: 3.3 parent: 84846:de7e4fd634fb user: Christian Heimes date: Fri Jul 26 23:04:29 2013 +0200 summary: Issue #18561: Skip name in ctypes' _build_callargs() if name is NULL. CID 486199 files: Misc/NEWS | 2 ++ Modules/_ctypes/_ctypes.c | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -54,6 +54,8 @@ Library ------- +- Issue #18561: Skip name in ctypes' _build_callargs() if name is NULL. + - Issue #18559: Fix NULL pointer dereference error in _pickle module - Issue #18556: Check the return value of a PyUnicode_AsWideChar() call in diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -3453,7 +3453,7 @@ Py_INCREF(v); return v; } - if (kwds && (v = PyDict_GetItem(kwds, name))) { + if (kwds && name && (v = PyDict_GetItem(kwds, name))) { ++*pindex; Py_INCREF(v); return v; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 26 23:04:53 2013 From: python-checkins at python.org (christian.heimes) Date: Fri, 26 Jul 2013 23:04:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318561=3A_Skip_name_in_ctypes=27_=5Fbuild=5Fcall?= =?utf-8?q?args=28=29_if_name_is_NULL=2E?= Message-ID: <3c22qT1XK6z7LjY@mail.python.org> http://hg.python.org/cpython/rev/d543829eda7d changeset: 84849:d543829eda7d parent: 84847:a5d9e2f3f6c7 parent: 84848:57457028dd7a user: Christian Heimes date: Fri Jul 26 23:04:39 2013 +0200 summary: Issue #18561: Skip name in ctypes' _build_callargs() if name is NULL. CID 486199 files: Misc/NEWS | 2 ++ Modules/_ctypes/_ctypes.c | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -168,6 +168,8 @@ Library ------- +- Issue #18561: Skip name in ctypes' _build_callargs() if name is NULL. + - Issue #18559: Fix NULL pointer dereference error in _pickle module - Issue #18556: Check the return type of PyUnicode_AsWideChar() in ctype's diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -3453,7 +3453,7 @@ Py_INCREF(v); return v; } - if (kwds && (v = PyDict_GetItem(kwds, name))) { + if (kwds && name && (v = PyDict_GetItem(kwds, name))) { ++*pindex; Py_INCREF(v); return v; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 00:01:56 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 00:01:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_According_to_t?= =?utf-8?q?he_PEP_7=2C_C_code_must_=22use_4-space_indents=22?= Message-ID: <3c245J0vV2z7LjM@mail.python.org> http://hg.python.org/cpython/rev/f2d557484906 changeset: 84850:f2d557484906 branch: 3.3 parent: 84848:57457028dd7a user: Victor Stinner date: Sat Jul 27 00:00:36 2013 +0200 summary: According to the PEP 7, C code must "use 4-space indents" Replace 8 spaces with 4. files: Include/Python-ast.h | 598 +- Parser/asdl_c.py | 2 +- Python/Python-ast.c | 11643 ++++++++++++++-------------- 3 files changed, 6099 insertions(+), 6144 deletions(-) diff --git a/Include/Python-ast.h b/Include/Python-ast.h --- a/Include/Python-ast.h +++ b/Include/Python-ast.h @@ -42,25 +42,25 @@ enum _mod_kind {Module_kind=1, Interactive_kind=2, Expression_kind=3, Suite_kind=4}; struct _mod { - enum _mod_kind kind; - union { - struct { - asdl_seq *body; - } Module; - - struct { - asdl_seq *body; - } Interactive; - - struct { - expr_ty body; - } Expression; - - struct { - asdl_seq *body; - } Suite; - - } v; + enum _mod_kind kind; + union { + struct { + asdl_seq *body; + } Module; + + struct { + asdl_seq *body; + } Interactive; + + struct { + expr_ty body; + } Expression; + + struct { + asdl_seq *body; + } Suite; + + } v; }; enum _stmt_kind {FunctionDef_kind=1, ClassDef_kind=2, Return_kind=3, @@ -70,111 +70,111 @@ ImportFrom_kind=15, Global_kind=16, Nonlocal_kind=17, Expr_kind=18, Pass_kind=19, Break_kind=20, Continue_kind=21}; struct _stmt { - enum _stmt_kind kind; - union { - struct { - identifier name; - arguments_ty args; - asdl_seq *body; - asdl_seq *decorator_list; - expr_ty returns; - } FunctionDef; - - struct { - identifier name; - asdl_seq *bases; - asdl_seq *keywords; - expr_ty starargs; - expr_ty kwargs; - asdl_seq *body; - asdl_seq *decorator_list; - } ClassDef; - - struct { - expr_ty value; - } Return; - - struct { - asdl_seq *targets; - } Delete; - - struct { - asdl_seq *targets; - expr_ty value; - } Assign; - - struct { - expr_ty target; - operator_ty op; - expr_ty value; - } AugAssign; - - struct { - expr_ty target; - expr_ty iter; - asdl_seq *body; - asdl_seq *orelse; - } For; - - struct { - expr_ty test; - asdl_seq *body; - asdl_seq *orelse; - } While; - - struct { - expr_ty test; - asdl_seq *body; - asdl_seq *orelse; - } If; - - struct { - asdl_seq *items; - asdl_seq *body; - } With; - - struct { - expr_ty exc; - expr_ty cause; - } Raise; - - struct { - asdl_seq *body; - asdl_seq *handlers; - asdl_seq *orelse; - asdl_seq *finalbody; - } Try; - - struct { - expr_ty test; - expr_ty msg; - } Assert; - - struct { - asdl_seq *names; - } Import; - - struct { - identifier module; - asdl_seq *names; - int level; - } ImportFrom; - - struct { - asdl_seq *names; - } Global; - - struct { - asdl_seq *names; - } Nonlocal; - - struct { - expr_ty value; - } Expr; - - } v; - int lineno; - int col_offset; + enum _stmt_kind kind; + union { + struct { + identifier name; + arguments_ty args; + asdl_seq *body; + asdl_seq *decorator_list; + expr_ty returns; + } FunctionDef; + + struct { + identifier name; + asdl_seq *bases; + asdl_seq *keywords; + expr_ty starargs; + expr_ty kwargs; + asdl_seq *body; + asdl_seq *decorator_list; + } ClassDef; + + struct { + expr_ty value; + } Return; + + struct { + asdl_seq *targets; + } Delete; + + struct { + asdl_seq *targets; + expr_ty value; + } Assign; + + struct { + expr_ty target; + operator_ty op; + expr_ty value; + } AugAssign; + + struct { + expr_ty target; + expr_ty iter; + asdl_seq *body; + asdl_seq *orelse; + } For; + + struct { + expr_ty test; + asdl_seq *body; + asdl_seq *orelse; + } While; + + struct { + expr_ty test; + asdl_seq *body; + asdl_seq *orelse; + } If; + + struct { + asdl_seq *items; + asdl_seq *body; + } With; + + struct { + expr_ty exc; + expr_ty cause; + } Raise; + + struct { + asdl_seq *body; + asdl_seq *handlers; + asdl_seq *orelse; + asdl_seq *finalbody; + } Try; + + struct { + expr_ty test; + expr_ty msg; + } Assert; + + struct { + asdl_seq *names; + } Import; + + struct { + identifier module; + asdl_seq *names; + int level; + } ImportFrom; + + struct { + asdl_seq *names; + } Global; + + struct { + asdl_seq *names; + } Nonlocal; + + struct { + expr_ty value; + } Expr; + + } v; + int lineno; + int col_offset; }; enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, @@ -185,207 +185,207 @@ Ellipsis_kind=19, Attribute_kind=20, Subscript_kind=21, Starred_kind=22, Name_kind=23, List_kind=24, Tuple_kind=25}; struct _expr { - enum _expr_kind kind; - union { - struct { - boolop_ty op; - asdl_seq *values; - } BoolOp; - - struct { - expr_ty left; - operator_ty op; - expr_ty right; - } BinOp; - - struct { - unaryop_ty op; - expr_ty operand; - } UnaryOp; - - struct { - arguments_ty args; - expr_ty body; - } Lambda; - - struct { - expr_ty test; - expr_ty body; - expr_ty orelse; - } IfExp; - - struct { - asdl_seq *keys; - asdl_seq *values; - } Dict; - - struct { - asdl_seq *elts; - } Set; - - struct { - expr_ty elt; - asdl_seq *generators; - } ListComp; - - struct { - expr_ty elt; - asdl_seq *generators; - } SetComp; - - struct { - expr_ty key; - expr_ty value; - asdl_seq *generators; - } DictComp; - - struct { - expr_ty elt; - asdl_seq *generators; - } GeneratorExp; - - struct { - expr_ty value; - } Yield; - - struct { - expr_ty value; - } YieldFrom; - - struct { - expr_ty left; - asdl_int_seq *ops; - asdl_seq *comparators; - } Compare; - - struct { - expr_ty func; - asdl_seq *args; - asdl_seq *keywords; - expr_ty starargs; - expr_ty kwargs; - } Call; - - struct { - object n; - } Num; - - struct { - string s; - } Str; - - struct { - bytes s; - } Bytes; - - struct { - expr_ty value; - identifier attr; - expr_context_ty ctx; - } Attribute; - - struct { - expr_ty value; - slice_ty slice; - expr_context_ty ctx; - } Subscript; - - struct { - expr_ty value; - expr_context_ty ctx; - } Starred; - - struct { - identifier id; - expr_context_ty ctx; - } Name; - - struct { - asdl_seq *elts; - expr_context_ty ctx; - } List; - - struct { - asdl_seq *elts; - expr_context_ty ctx; - } Tuple; - - } v; - int lineno; - int col_offset; + enum _expr_kind kind; + union { + struct { + boolop_ty op; + asdl_seq *values; + } BoolOp; + + struct { + expr_ty left; + operator_ty op; + expr_ty right; + } BinOp; + + struct { + unaryop_ty op; + expr_ty operand; + } UnaryOp; + + struct { + arguments_ty args; + expr_ty body; + } Lambda; + + struct { + expr_ty test; + expr_ty body; + expr_ty orelse; + } IfExp; + + struct { + asdl_seq *keys; + asdl_seq *values; + } Dict; + + struct { + asdl_seq *elts; + } Set; + + struct { + expr_ty elt; + asdl_seq *generators; + } ListComp; + + struct { + expr_ty elt; + asdl_seq *generators; + } SetComp; + + struct { + expr_ty key; + expr_ty value; + asdl_seq *generators; + } DictComp; + + struct { + expr_ty elt; + asdl_seq *generators; + } GeneratorExp; + + struct { + expr_ty value; + } Yield; + + struct { + expr_ty value; + } YieldFrom; + + struct { + expr_ty left; + asdl_int_seq *ops; + asdl_seq *comparators; + } Compare; + + struct { + expr_ty func; + asdl_seq *args; + asdl_seq *keywords; + expr_ty starargs; + expr_ty kwargs; + } Call; + + struct { + object n; + } Num; + + struct { + string s; + } Str; + + struct { + bytes s; + } Bytes; + + struct { + expr_ty value; + identifier attr; + expr_context_ty ctx; + } Attribute; + + struct { + expr_ty value; + slice_ty slice; + expr_context_ty ctx; + } Subscript; + + struct { + expr_ty value; + expr_context_ty ctx; + } Starred; + + struct { + identifier id; + expr_context_ty ctx; + } Name; + + struct { + asdl_seq *elts; + expr_context_ty ctx; + } List; + + struct { + asdl_seq *elts; + expr_context_ty ctx; + } Tuple; + + } v; + int lineno; + int col_offset; }; enum _slice_kind {Slice_kind=1, ExtSlice_kind=2, Index_kind=3}; struct _slice { - enum _slice_kind kind; - union { - struct { - expr_ty lower; - expr_ty upper; - expr_ty step; - } Slice; - - struct { - asdl_seq *dims; - } ExtSlice; - - struct { - expr_ty value; - } Index; - - } v; + enum _slice_kind kind; + union { + struct { + expr_ty lower; + expr_ty upper; + expr_ty step; + } Slice; + + struct { + asdl_seq *dims; + } ExtSlice; + + struct { + expr_ty value; + } Index; + + } v; }; struct _comprehension { - expr_ty target; - expr_ty iter; - asdl_seq *ifs; + expr_ty target; + expr_ty iter; + asdl_seq *ifs; }; enum _excepthandler_kind {ExceptHandler_kind=1}; struct _excepthandler { - enum _excepthandler_kind kind; - union { - struct { - expr_ty type; - identifier name; - asdl_seq *body; - } ExceptHandler; - - } v; - int lineno; - int col_offset; + enum _excepthandler_kind kind; + union { + struct { + expr_ty type; + identifier name; + asdl_seq *body; + } ExceptHandler; + + } v; + int lineno; + int col_offset; }; struct _arguments { - asdl_seq *args; - identifier vararg; - expr_ty varargannotation; - asdl_seq *kwonlyargs; - identifier kwarg; - expr_ty kwargannotation; - asdl_seq *defaults; - asdl_seq *kw_defaults; + asdl_seq *args; + identifier vararg; + expr_ty varargannotation; + asdl_seq *kwonlyargs; + identifier kwarg; + expr_ty kwargannotation; + asdl_seq *defaults; + asdl_seq *kw_defaults; }; struct _arg { - identifier arg; - expr_ty annotation; + identifier arg; + expr_ty annotation; }; struct _keyword { - identifier arg; - expr_ty value; + identifier arg; + expr_ty value; }; struct _alias { - identifier name; - identifier asname; + identifier name; + identifier asname; }; struct _withitem { - expr_ty context_expr; - expr_ty optional_vars; + expr_ty context_expr; + expr_ty optional_vars; }; diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -8,7 +8,7 @@ import asdl -TABSIZE = 8 +TABSIZE = 4 MAX_COL = 80 def get_c_type(name): diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -11,26 +11,26 @@ static PyTypeObject *Module_type; _Py_IDENTIFIER(body); static char *Module_fields[]={ - "body", + "body", }; static PyTypeObject *Interactive_type; static char *Interactive_fields[]={ - "body", + "body", }; static PyTypeObject *Expression_type; static char *Expression_fields[]={ - "body", + "body", }; static PyTypeObject *Suite_type; static char *Suite_fields[]={ - "body", + "body", }; static PyTypeObject *stmt_type; _Py_IDENTIFIER(lineno); _Py_IDENTIFIER(col_offset); static char *stmt_attributes[] = { - "lineno", - "col_offset", + "lineno", + "col_offset", }; static PyObject* ast2obj_stmt(void*); static PyTypeObject *FunctionDef_type; @@ -39,11 +39,11 @@ _Py_IDENTIFIER(decorator_list); _Py_IDENTIFIER(returns); static char *FunctionDef_fields[]={ - "name", - "args", - "body", - "decorator_list", - "returns", + "name", + "args", + "body", + "decorator_list", + "returns", }; static PyTypeObject *ClassDef_type; _Py_IDENTIFIER(bases); @@ -51,262 +51,262 @@ _Py_IDENTIFIER(starargs); _Py_IDENTIFIER(kwargs); static char *ClassDef_fields[]={ - "name", - "bases", - "keywords", - "starargs", - "kwargs", - "body", - "decorator_list", + "name", + "bases", + "keywords", + "starargs", + "kwargs", + "body", + "decorator_list", }; static PyTypeObject *Return_type; _Py_IDENTIFIER(value); static char *Return_fields[]={ - "value", + "value", }; static PyTypeObject *Delete_type; _Py_IDENTIFIER(targets); static char *Delete_fields[]={ - "targets", + "targets", }; static PyTypeObject *Assign_type; static char *Assign_fields[]={ - "targets", - "value", + "targets", + "value", }; static PyTypeObject *AugAssign_type; _Py_IDENTIFIER(target); _Py_IDENTIFIER(op); static char *AugAssign_fields[]={ - "target", - "op", - "value", + "target", + "op", + "value", }; static PyTypeObject *For_type; _Py_IDENTIFIER(iter); _Py_IDENTIFIER(orelse); static char *For_fields[]={ - "target", - "iter", - "body", - "orelse", + "target", + "iter", + "body", + "orelse", }; static PyTypeObject *While_type; _Py_IDENTIFIER(test); static char *While_fields[]={ - "test", - "body", - "orelse", + "test", + "body", + "orelse", }; static PyTypeObject *If_type; static char *If_fields[]={ - "test", - "body", - "orelse", + "test", + "body", + "orelse", }; static PyTypeObject *With_type; _Py_IDENTIFIER(items); static char *With_fields[]={ - "items", - "body", + "items", + "body", }; static PyTypeObject *Raise_type; _Py_IDENTIFIER(exc); _Py_IDENTIFIER(cause); static char *Raise_fields[]={ - "exc", - "cause", + "exc", + "cause", }; static PyTypeObject *Try_type; _Py_IDENTIFIER(handlers); _Py_IDENTIFIER(finalbody); static char *Try_fields[]={ - "body", - "handlers", - "orelse", - "finalbody", + "body", + "handlers", + "orelse", + "finalbody", }; static PyTypeObject *Assert_type; _Py_IDENTIFIER(msg); static char *Assert_fields[]={ - "test", - "msg", + "test", + "msg", }; static PyTypeObject *Import_type; _Py_IDENTIFIER(names); static char *Import_fields[]={ - "names", + "names", }; static PyTypeObject *ImportFrom_type; _Py_IDENTIFIER(module); _Py_IDENTIFIER(level); static char *ImportFrom_fields[]={ - "module", - "names", - "level", + "module", + "names", + "level", }; static PyTypeObject *Global_type; static char *Global_fields[]={ - "names", + "names", }; static PyTypeObject *Nonlocal_type; static char *Nonlocal_fields[]={ - "names", + "names", }; static PyTypeObject *Expr_type; static char *Expr_fields[]={ - "value", + "value", }; static PyTypeObject *Pass_type; static PyTypeObject *Break_type; static PyTypeObject *Continue_type; static PyTypeObject *expr_type; static char *expr_attributes[] = { - "lineno", - "col_offset", + "lineno", + "col_offset", }; static PyObject* ast2obj_expr(void*); static PyTypeObject *BoolOp_type; _Py_IDENTIFIER(values); static char *BoolOp_fields[]={ - "op", - "values", + "op", + "values", }; static PyTypeObject *BinOp_type; _Py_IDENTIFIER(left); _Py_IDENTIFIER(right); static char *BinOp_fields[]={ - "left", - "op", - "right", + "left", + "op", + "right", }; static PyTypeObject *UnaryOp_type; _Py_IDENTIFIER(operand); static char *UnaryOp_fields[]={ - "op", - "operand", + "op", + "operand", }; static PyTypeObject *Lambda_type; static char *Lambda_fields[]={ - "args", - "body", + "args", + "body", }; static PyTypeObject *IfExp_type; static char *IfExp_fields[]={ - "test", - "body", - "orelse", + "test", + "body", + "orelse", }; static PyTypeObject *Dict_type; _Py_IDENTIFIER(keys); static char *Dict_fields[]={ - "keys", - "values", + "keys", + "values", }; static PyTypeObject *Set_type; _Py_IDENTIFIER(elts); static char *Set_fields[]={ - "elts", + "elts", }; static PyTypeObject *ListComp_type; _Py_IDENTIFIER(elt); _Py_IDENTIFIER(generators); static char *ListComp_fields[]={ - "elt", - "generators", + "elt", + "generators", }; static PyTypeObject *SetComp_type; static char *SetComp_fields[]={ - "elt", - "generators", + "elt", + "generators", }; static PyTypeObject *DictComp_type; _Py_IDENTIFIER(key); static char *DictComp_fields[]={ - "key", - "value", - "generators", + "key", + "value", + "generators", }; static PyTypeObject *GeneratorExp_type; static char *GeneratorExp_fields[]={ - "elt", - "generators", + "elt", + "generators", }; static PyTypeObject *Yield_type; static char *Yield_fields[]={ - "value", + "value", }; static PyTypeObject *YieldFrom_type; static char *YieldFrom_fields[]={ - "value", + "value", }; static PyTypeObject *Compare_type; _Py_IDENTIFIER(ops); _Py_IDENTIFIER(comparators); static char *Compare_fields[]={ - "left", - "ops", - "comparators", + "left", + "ops", + "comparators", }; static PyTypeObject *Call_type; _Py_IDENTIFIER(func); static char *Call_fields[]={ - "func", - "args", - "keywords", - "starargs", - "kwargs", + "func", + "args", + "keywords", + "starargs", + "kwargs", }; static PyTypeObject *Num_type; _Py_IDENTIFIER(n); static char *Num_fields[]={ - "n", + "n", }; static PyTypeObject *Str_type; _Py_IDENTIFIER(s); static char *Str_fields[]={ - "s", + "s", }; static PyTypeObject *Bytes_type; static char *Bytes_fields[]={ - "s", + "s", }; static PyTypeObject *Ellipsis_type; static PyTypeObject *Attribute_type; _Py_IDENTIFIER(attr); _Py_IDENTIFIER(ctx); static char *Attribute_fields[]={ - "value", - "attr", - "ctx", + "value", + "attr", + "ctx", }; static PyTypeObject *Subscript_type; _Py_IDENTIFIER(slice); static char *Subscript_fields[]={ - "value", - "slice", - "ctx", + "value", + "slice", + "ctx", }; static PyTypeObject *Starred_type; static char *Starred_fields[]={ - "value", - "ctx", + "value", + "ctx", }; static PyTypeObject *Name_type; _Py_IDENTIFIER(id); static char *Name_fields[]={ - "id", - "ctx", + "id", + "ctx", }; static PyTypeObject *List_type; static char *List_fields[]={ - "elts", - "ctx", + "elts", + "ctx", }; static PyTypeObject *Tuple_type; static char *Tuple_fields[]={ - "elts", - "ctx", + "elts", + "ctx", }; static PyTypeObject *expr_context_type; static PyObject *Load_singleton, *Store_singleton, *Del_singleton, @@ -325,18 +325,18 @@ _Py_IDENTIFIER(upper); _Py_IDENTIFIER(step); static char *Slice_fields[]={ - "lower", - "upper", - "step", + "lower", + "upper", + "step", }; static PyTypeObject *ExtSlice_type; _Py_IDENTIFIER(dims); static char *ExtSlice_fields[]={ - "dims", + "dims", }; static PyTypeObject *Index_type; static char *Index_fields[]={ - "value", + "value", }; static PyTypeObject *boolop_type; static PyObject *And_singleton, *Or_singleton; @@ -388,22 +388,22 @@ static PyObject* ast2obj_comprehension(void*); _Py_IDENTIFIER(ifs); static char *comprehension_fields[]={ - "target", - "iter", - "ifs", + "target", + "iter", + "ifs", }; static PyTypeObject *excepthandler_type; static char *excepthandler_attributes[] = { - "lineno", - "col_offset", + "lineno", + "col_offset", }; static PyObject* ast2obj_excepthandler(void*); static PyTypeObject *ExceptHandler_type; _Py_IDENTIFIER(type); static char *ExceptHandler_fields[]={ - "type", - "name", - "body", + "type", + "name", + "body", }; static PyTypeObject *arguments_type; static PyObject* ast2obj_arguments(void*); @@ -415,43 +415,43 @@ _Py_IDENTIFIER(defaults); _Py_IDENTIFIER(kw_defaults); static char *arguments_fields[]={ - "args", - "vararg", - "varargannotation", - "kwonlyargs", - "kwarg", - "kwargannotation", - "defaults", - "kw_defaults", + "args", + "vararg", + "varargannotation", + "kwonlyargs", + "kwarg", + "kwargannotation", + "defaults", + "kw_defaults", }; static PyTypeObject *arg_type; static PyObject* ast2obj_arg(void*); _Py_IDENTIFIER(arg); _Py_IDENTIFIER(annotation); static char *arg_fields[]={ - "arg", - "annotation", + "arg", + "annotation", }; static PyTypeObject *keyword_type; static PyObject* ast2obj_keyword(void*); static char *keyword_fields[]={ - "arg", - "value", + "arg", + "value", }; static PyTypeObject *alias_type; static PyObject* ast2obj_alias(void*); _Py_IDENTIFIER(asname); static char *alias_fields[]={ - "name", - "asname", + "name", + "asname", }; static PyTypeObject *withitem_type; static PyObject* ast2obj_withitem(void*); _Py_IDENTIFIER(context_expr); _Py_IDENTIFIER(optional_vars); static char *withitem_fields[]={ - "context_expr", - "optional_vars", + "context_expr", + "optional_vars", }; @@ -757,305 +757,303 @@ static int init_types(void) { - static int initialized; - if (initialized) return 1; - if (add_ast_fields() < 0) return 0; - mod_type = make_type("mod", &AST_type, NULL, 0); - if (!mod_type) return 0; - if (!add_attributes(mod_type, NULL, 0)) return 0; - Module_type = make_type("Module", mod_type, Module_fields, 1); - if (!Module_type) return 0; - Interactive_type = make_type("Interactive", mod_type, - Interactive_fields, 1); - if (!Interactive_type) return 0; - Expression_type = make_type("Expression", mod_type, Expression_fields, - 1); - if (!Expression_type) return 0; - Suite_type = make_type("Suite", mod_type, Suite_fields, 1); - if (!Suite_type) return 0; - stmt_type = make_type("stmt", &AST_type, NULL, 0); - if (!stmt_type) return 0; - if (!add_attributes(stmt_type, stmt_attributes, 2)) return 0; - FunctionDef_type = make_type("FunctionDef", stmt_type, - FunctionDef_fields, 5); - if (!FunctionDef_type) return 0; - ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 7); - if (!ClassDef_type) return 0; - Return_type = make_type("Return", stmt_type, Return_fields, 1); - if (!Return_type) return 0; - Delete_type = make_type("Delete", stmt_type, Delete_fields, 1); - if (!Delete_type) return 0; - Assign_type = make_type("Assign", stmt_type, Assign_fields, 2); - if (!Assign_type) return 0; - AugAssign_type = make_type("AugAssign", stmt_type, AugAssign_fields, 3); - if (!AugAssign_type) return 0; - For_type = make_type("For", stmt_type, For_fields, 4); - if (!For_type) return 0; - While_type = make_type("While", stmt_type, While_fields, 3); - if (!While_type) return 0; - If_type = make_type("If", stmt_type, If_fields, 3); - if (!If_type) return 0; - With_type = make_type("With", stmt_type, With_fields, 2); - if (!With_type) return 0; - Raise_type = make_type("Raise", stmt_type, Raise_fields, 2); - if (!Raise_type) return 0; - Try_type = make_type("Try", stmt_type, Try_fields, 4); - if (!Try_type) return 0; - Assert_type = make_type("Assert", stmt_type, Assert_fields, 2); - if (!Assert_type) return 0; - Import_type = make_type("Import", stmt_type, Import_fields, 1); - if (!Import_type) return 0; - ImportFrom_type = make_type("ImportFrom", stmt_type, ImportFrom_fields, - 3); - if (!ImportFrom_type) return 0; - Global_type = make_type("Global", stmt_type, Global_fields, 1); - if (!Global_type) return 0; - Nonlocal_type = make_type("Nonlocal", stmt_type, Nonlocal_fields, 1); - if (!Nonlocal_type) return 0; - Expr_type = make_type("Expr", stmt_type, Expr_fields, 1); - if (!Expr_type) return 0; - Pass_type = make_type("Pass", stmt_type, NULL, 0); - if (!Pass_type) return 0; - Break_type = make_type("Break", stmt_type, NULL, 0); - if (!Break_type) return 0; - Continue_type = make_type("Continue", stmt_type, NULL, 0); - if (!Continue_type) return 0; - expr_type = make_type("expr", &AST_type, NULL, 0); - if (!expr_type) return 0; - if (!add_attributes(expr_type, expr_attributes, 2)) return 0; - BoolOp_type = make_type("BoolOp", expr_type, BoolOp_fields, 2); - if (!BoolOp_type) return 0; - BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3); - if (!BinOp_type) return 0; - UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2); - if (!UnaryOp_type) return 0; - Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2); - if (!Lambda_type) return 0; - IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3); - if (!IfExp_type) return 0; - Dict_type = make_type("Dict", expr_type, Dict_fields, 2); - if (!Dict_type) return 0; - Set_type = make_type("Set", expr_type, Set_fields, 1); - if (!Set_type) return 0; - ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2); - if (!ListComp_type) return 0; - SetComp_type = make_type("SetComp", expr_type, SetComp_fields, 2); - if (!SetComp_type) return 0; - DictComp_type = make_type("DictComp", expr_type, DictComp_fields, 3); - if (!DictComp_type) return 0; - GeneratorExp_type = make_type("GeneratorExp", expr_type, - GeneratorExp_fields, 2); - if (!GeneratorExp_type) return 0; - Yield_type = make_type("Yield", expr_type, Yield_fields, 1); - if (!Yield_type) return 0; - YieldFrom_type = make_type("YieldFrom", expr_type, YieldFrom_fields, 1); - if (!YieldFrom_type) return 0; - Compare_type = make_type("Compare", expr_type, Compare_fields, 3); - if (!Compare_type) return 0; - Call_type = make_type("Call", expr_type, Call_fields, 5); - if (!Call_type) return 0; - Num_type = make_type("Num", expr_type, Num_fields, 1); - if (!Num_type) return 0; - Str_type = make_type("Str", expr_type, Str_fields, 1); - if (!Str_type) return 0; - Bytes_type = make_type("Bytes", expr_type, Bytes_fields, 1); - if (!Bytes_type) return 0; - Ellipsis_type = make_type("Ellipsis", expr_type, NULL, 0); - if (!Ellipsis_type) return 0; - Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3); - if (!Attribute_type) return 0; - Subscript_type = make_type("Subscript", expr_type, Subscript_fields, 3); - if (!Subscript_type) return 0; - Starred_type = make_type("Starred", expr_type, Starred_fields, 2); - if (!Starred_type) return 0; - Name_type = make_type("Name", expr_type, Name_fields, 2); - if (!Name_type) return 0; - List_type = make_type("List", expr_type, List_fields, 2); - if (!List_type) return 0; - Tuple_type = make_type("Tuple", expr_type, Tuple_fields, 2); - if (!Tuple_type) return 0; - expr_context_type = make_type("expr_context", &AST_type, NULL, 0); - if (!expr_context_type) return 0; - if (!add_attributes(expr_context_type, NULL, 0)) return 0; - Load_type = make_type("Load", expr_context_type, NULL, 0); - if (!Load_type) return 0; - Load_singleton = PyType_GenericNew(Load_type, NULL, NULL); - if (!Load_singleton) return 0; - Store_type = make_type("Store", expr_context_type, NULL, 0); - if (!Store_type) return 0; - Store_singleton = PyType_GenericNew(Store_type, NULL, NULL); - if (!Store_singleton) return 0; - Del_type = make_type("Del", expr_context_type, NULL, 0); - if (!Del_type) return 0; - Del_singleton = PyType_GenericNew(Del_type, NULL, NULL); - if (!Del_singleton) return 0; - AugLoad_type = make_type("AugLoad", expr_context_type, NULL, 0); - if (!AugLoad_type) return 0; - AugLoad_singleton = PyType_GenericNew(AugLoad_type, NULL, NULL); - if (!AugLoad_singleton) return 0; - AugStore_type = make_type("AugStore", expr_context_type, NULL, 0); - if (!AugStore_type) return 0; - AugStore_singleton = PyType_GenericNew(AugStore_type, NULL, NULL); - if (!AugStore_singleton) return 0; - Param_type = make_type("Param", expr_context_type, NULL, 0); - if (!Param_type) return 0; - Param_singleton = PyType_GenericNew(Param_type, NULL, NULL); - if (!Param_singleton) return 0; - slice_type = make_type("slice", &AST_type, NULL, 0); - if (!slice_type) return 0; - if (!add_attributes(slice_type, NULL, 0)) return 0; - Slice_type = make_type("Slice", slice_type, Slice_fields, 3); - if (!Slice_type) return 0; - ExtSlice_type = make_type("ExtSlice", slice_type, ExtSlice_fields, 1); - if (!ExtSlice_type) return 0; - Index_type = make_type("Index", slice_type, Index_fields, 1); - if (!Index_type) return 0; - boolop_type = make_type("boolop", &AST_type, NULL, 0); - if (!boolop_type) return 0; - if (!add_attributes(boolop_type, NULL, 0)) return 0; - And_type = make_type("And", boolop_type, NULL, 0); - if (!And_type) return 0; - And_singleton = PyType_GenericNew(And_type, NULL, NULL); - if (!And_singleton) return 0; - Or_type = make_type("Or", boolop_type, NULL, 0); - if (!Or_type) return 0; - Or_singleton = PyType_GenericNew(Or_type, NULL, NULL); - if (!Or_singleton) return 0; - operator_type = make_type("operator", &AST_type, NULL, 0); - if (!operator_type) return 0; - if (!add_attributes(operator_type, NULL, 0)) return 0; - Add_type = make_type("Add", operator_type, NULL, 0); - if (!Add_type) return 0; - Add_singleton = PyType_GenericNew(Add_type, NULL, NULL); - if (!Add_singleton) return 0; - Sub_type = make_type("Sub", operator_type, NULL, 0); - if (!Sub_type) return 0; - Sub_singleton = PyType_GenericNew(Sub_type, NULL, NULL); - if (!Sub_singleton) return 0; - Mult_type = make_type("Mult", operator_type, NULL, 0); - if (!Mult_type) return 0; - Mult_singleton = PyType_GenericNew(Mult_type, NULL, NULL); - if (!Mult_singleton) return 0; - Div_type = make_type("Div", operator_type, NULL, 0); - if (!Div_type) return 0; - Div_singleton = PyType_GenericNew(Div_type, NULL, NULL); - if (!Div_singleton) return 0; - Mod_type = make_type("Mod", operator_type, NULL, 0); - if (!Mod_type) return 0; - Mod_singleton = PyType_GenericNew(Mod_type, NULL, NULL); - if (!Mod_singleton) return 0; - Pow_type = make_type("Pow", operator_type, NULL, 0); - if (!Pow_type) return 0; - Pow_singleton = PyType_GenericNew(Pow_type, NULL, NULL); - if (!Pow_singleton) return 0; - LShift_type = make_type("LShift", operator_type, NULL, 0); - if (!LShift_type) return 0; - LShift_singleton = PyType_GenericNew(LShift_type, NULL, NULL); - if (!LShift_singleton) return 0; - RShift_type = make_type("RShift", operator_type, NULL, 0); - if (!RShift_type) return 0; - RShift_singleton = PyType_GenericNew(RShift_type, NULL, NULL); - if (!RShift_singleton) return 0; - BitOr_type = make_type("BitOr", operator_type, NULL, 0); - if (!BitOr_type) return 0; - BitOr_singleton = PyType_GenericNew(BitOr_type, NULL, NULL); - if (!BitOr_singleton) return 0; - BitXor_type = make_type("BitXor", operator_type, NULL, 0); - if (!BitXor_type) return 0; - BitXor_singleton = PyType_GenericNew(BitXor_type, NULL, NULL); - if (!BitXor_singleton) return 0; - BitAnd_type = make_type("BitAnd", operator_type, NULL, 0); - if (!BitAnd_type) return 0; - BitAnd_singleton = PyType_GenericNew(BitAnd_type, NULL, NULL); - if (!BitAnd_singleton) return 0; - FloorDiv_type = make_type("FloorDiv", operator_type, NULL, 0); - if (!FloorDiv_type) return 0; - FloorDiv_singleton = PyType_GenericNew(FloorDiv_type, NULL, NULL); - if (!FloorDiv_singleton) return 0; - unaryop_type = make_type("unaryop", &AST_type, NULL, 0); - if (!unaryop_type) return 0; - if (!add_attributes(unaryop_type, NULL, 0)) return 0; - Invert_type = make_type("Invert", unaryop_type, NULL, 0); - if (!Invert_type) return 0; - Invert_singleton = PyType_GenericNew(Invert_type, NULL, NULL); - if (!Invert_singleton) return 0; - Not_type = make_type("Not", unaryop_type, NULL, 0); - if (!Not_type) return 0; - Not_singleton = PyType_GenericNew(Not_type, NULL, NULL); - if (!Not_singleton) return 0; - UAdd_type = make_type("UAdd", unaryop_type, NULL, 0); - if (!UAdd_type) return 0; - UAdd_singleton = PyType_GenericNew(UAdd_type, NULL, NULL); - if (!UAdd_singleton) return 0; - USub_type = make_type("USub", unaryop_type, NULL, 0); - if (!USub_type) return 0; - USub_singleton = PyType_GenericNew(USub_type, NULL, NULL); - if (!USub_singleton) return 0; - cmpop_type = make_type("cmpop", &AST_type, NULL, 0); - if (!cmpop_type) return 0; - if (!add_attributes(cmpop_type, NULL, 0)) return 0; - Eq_type = make_type("Eq", cmpop_type, NULL, 0); - if (!Eq_type) return 0; - Eq_singleton = PyType_GenericNew(Eq_type, NULL, NULL); - if (!Eq_singleton) return 0; - NotEq_type = make_type("NotEq", cmpop_type, NULL, 0); - if (!NotEq_type) return 0; - NotEq_singleton = PyType_GenericNew(NotEq_type, NULL, NULL); - if (!NotEq_singleton) return 0; - Lt_type = make_type("Lt", cmpop_type, NULL, 0); - if (!Lt_type) return 0; - Lt_singleton = PyType_GenericNew(Lt_type, NULL, NULL); - if (!Lt_singleton) return 0; - LtE_type = make_type("LtE", cmpop_type, NULL, 0); - if (!LtE_type) return 0; - LtE_singleton = PyType_GenericNew(LtE_type, NULL, NULL); - if (!LtE_singleton) return 0; - Gt_type = make_type("Gt", cmpop_type, NULL, 0); - if (!Gt_type) return 0; - Gt_singleton = PyType_GenericNew(Gt_type, NULL, NULL); - if (!Gt_singleton) return 0; - GtE_type = make_type("GtE", cmpop_type, NULL, 0); - if (!GtE_type) return 0; - GtE_singleton = PyType_GenericNew(GtE_type, NULL, NULL); - if (!GtE_singleton) return 0; - Is_type = make_type("Is", cmpop_type, NULL, 0); - if (!Is_type) return 0; - Is_singleton = PyType_GenericNew(Is_type, NULL, NULL); - if (!Is_singleton) return 0; - IsNot_type = make_type("IsNot", cmpop_type, NULL, 0); - if (!IsNot_type) return 0; - IsNot_singleton = PyType_GenericNew(IsNot_type, NULL, NULL); - if (!IsNot_singleton) return 0; - In_type = make_type("In", cmpop_type, NULL, 0); - if (!In_type) return 0; - In_singleton = PyType_GenericNew(In_type, NULL, NULL); - if (!In_singleton) return 0; - NotIn_type = make_type("NotIn", cmpop_type, NULL, 0); - if (!NotIn_type) return 0; - NotIn_singleton = PyType_GenericNew(NotIn_type, NULL, NULL); - if (!NotIn_singleton) return 0; - comprehension_type = make_type("comprehension", &AST_type, - comprehension_fields, 3); - if (!comprehension_type) return 0; - excepthandler_type = make_type("excepthandler", &AST_type, NULL, 0); - if (!excepthandler_type) return 0; - if (!add_attributes(excepthandler_type, excepthandler_attributes, 2)) - return 0; - ExceptHandler_type = make_type("ExceptHandler", excepthandler_type, - ExceptHandler_fields, 3); - if (!ExceptHandler_type) return 0; - arguments_type = make_type("arguments", &AST_type, arguments_fields, 8); - if (!arguments_type) return 0; - arg_type = make_type("arg", &AST_type, arg_fields, 2); - if (!arg_type) return 0; - keyword_type = make_type("keyword", &AST_type, keyword_fields, 2); - if (!keyword_type) return 0; - alias_type = make_type("alias", &AST_type, alias_fields, 2); - if (!alias_type) return 0; - withitem_type = make_type("withitem", &AST_type, withitem_fields, 2); - if (!withitem_type) return 0; - initialized = 1; - return 1; + static int initialized; + if (initialized) return 1; + if (add_ast_fields() < 0) return 0; + mod_type = make_type("mod", &AST_type, NULL, 0); + if (!mod_type) return 0; + if (!add_attributes(mod_type, NULL, 0)) return 0; + Module_type = make_type("Module", mod_type, Module_fields, 1); + if (!Module_type) return 0; + Interactive_type = make_type("Interactive", mod_type, Interactive_fields, + 1); + if (!Interactive_type) return 0; + Expression_type = make_type("Expression", mod_type, Expression_fields, 1); + if (!Expression_type) return 0; + Suite_type = make_type("Suite", mod_type, Suite_fields, 1); + if (!Suite_type) return 0; + stmt_type = make_type("stmt", &AST_type, NULL, 0); + if (!stmt_type) return 0; + if (!add_attributes(stmt_type, stmt_attributes, 2)) return 0; + FunctionDef_type = make_type("FunctionDef", stmt_type, FunctionDef_fields, + 5); + if (!FunctionDef_type) return 0; + ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 7); + if (!ClassDef_type) return 0; + Return_type = make_type("Return", stmt_type, Return_fields, 1); + if (!Return_type) return 0; + Delete_type = make_type("Delete", stmt_type, Delete_fields, 1); + if (!Delete_type) return 0; + Assign_type = make_type("Assign", stmt_type, Assign_fields, 2); + if (!Assign_type) return 0; + AugAssign_type = make_type("AugAssign", stmt_type, AugAssign_fields, 3); + if (!AugAssign_type) return 0; + For_type = make_type("For", stmt_type, For_fields, 4); + if (!For_type) return 0; + While_type = make_type("While", stmt_type, While_fields, 3); + if (!While_type) return 0; + If_type = make_type("If", stmt_type, If_fields, 3); + if (!If_type) return 0; + With_type = make_type("With", stmt_type, With_fields, 2); + if (!With_type) return 0; + Raise_type = make_type("Raise", stmt_type, Raise_fields, 2); + if (!Raise_type) return 0; + Try_type = make_type("Try", stmt_type, Try_fields, 4); + if (!Try_type) return 0; + Assert_type = make_type("Assert", stmt_type, Assert_fields, 2); + if (!Assert_type) return 0; + Import_type = make_type("Import", stmt_type, Import_fields, 1); + if (!Import_type) return 0; + ImportFrom_type = make_type("ImportFrom", stmt_type, ImportFrom_fields, 3); + if (!ImportFrom_type) return 0; + Global_type = make_type("Global", stmt_type, Global_fields, 1); + if (!Global_type) return 0; + Nonlocal_type = make_type("Nonlocal", stmt_type, Nonlocal_fields, 1); + if (!Nonlocal_type) return 0; + Expr_type = make_type("Expr", stmt_type, Expr_fields, 1); + if (!Expr_type) return 0; + Pass_type = make_type("Pass", stmt_type, NULL, 0); + if (!Pass_type) return 0; + Break_type = make_type("Break", stmt_type, NULL, 0); + if (!Break_type) return 0; + Continue_type = make_type("Continue", stmt_type, NULL, 0); + if (!Continue_type) return 0; + expr_type = make_type("expr", &AST_type, NULL, 0); + if (!expr_type) return 0; + if (!add_attributes(expr_type, expr_attributes, 2)) return 0; + BoolOp_type = make_type("BoolOp", expr_type, BoolOp_fields, 2); + if (!BoolOp_type) return 0; + BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3); + if (!BinOp_type) return 0; + UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2); + if (!UnaryOp_type) return 0; + Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2); + if (!Lambda_type) return 0; + IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3); + if (!IfExp_type) return 0; + Dict_type = make_type("Dict", expr_type, Dict_fields, 2); + if (!Dict_type) return 0; + Set_type = make_type("Set", expr_type, Set_fields, 1); + if (!Set_type) return 0; + ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2); + if (!ListComp_type) return 0; + SetComp_type = make_type("SetComp", expr_type, SetComp_fields, 2); + if (!SetComp_type) return 0; + DictComp_type = make_type("DictComp", expr_type, DictComp_fields, 3); + if (!DictComp_type) return 0; + GeneratorExp_type = make_type("GeneratorExp", expr_type, + GeneratorExp_fields, 2); + if (!GeneratorExp_type) return 0; + Yield_type = make_type("Yield", expr_type, Yield_fields, 1); + if (!Yield_type) return 0; + YieldFrom_type = make_type("YieldFrom", expr_type, YieldFrom_fields, 1); + if (!YieldFrom_type) return 0; + Compare_type = make_type("Compare", expr_type, Compare_fields, 3); + if (!Compare_type) return 0; + Call_type = make_type("Call", expr_type, Call_fields, 5); + if (!Call_type) return 0; + Num_type = make_type("Num", expr_type, Num_fields, 1); + if (!Num_type) return 0; + Str_type = make_type("Str", expr_type, Str_fields, 1); + if (!Str_type) return 0; + Bytes_type = make_type("Bytes", expr_type, Bytes_fields, 1); + if (!Bytes_type) return 0; + Ellipsis_type = make_type("Ellipsis", expr_type, NULL, 0); + if (!Ellipsis_type) return 0; + Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3); + if (!Attribute_type) return 0; + Subscript_type = make_type("Subscript", expr_type, Subscript_fields, 3); + if (!Subscript_type) return 0; + Starred_type = make_type("Starred", expr_type, Starred_fields, 2); + if (!Starred_type) return 0; + Name_type = make_type("Name", expr_type, Name_fields, 2); + if (!Name_type) return 0; + List_type = make_type("List", expr_type, List_fields, 2); + if (!List_type) return 0; + Tuple_type = make_type("Tuple", expr_type, Tuple_fields, 2); + if (!Tuple_type) return 0; + expr_context_type = make_type("expr_context", &AST_type, NULL, 0); + if (!expr_context_type) return 0; + if (!add_attributes(expr_context_type, NULL, 0)) return 0; + Load_type = make_type("Load", expr_context_type, NULL, 0); + if (!Load_type) return 0; + Load_singleton = PyType_GenericNew(Load_type, NULL, NULL); + if (!Load_singleton) return 0; + Store_type = make_type("Store", expr_context_type, NULL, 0); + if (!Store_type) return 0; + Store_singleton = PyType_GenericNew(Store_type, NULL, NULL); + if (!Store_singleton) return 0; + Del_type = make_type("Del", expr_context_type, NULL, 0); + if (!Del_type) return 0; + Del_singleton = PyType_GenericNew(Del_type, NULL, NULL); + if (!Del_singleton) return 0; + AugLoad_type = make_type("AugLoad", expr_context_type, NULL, 0); + if (!AugLoad_type) return 0; + AugLoad_singleton = PyType_GenericNew(AugLoad_type, NULL, NULL); + if (!AugLoad_singleton) return 0; + AugStore_type = make_type("AugStore", expr_context_type, NULL, 0); + if (!AugStore_type) return 0; + AugStore_singleton = PyType_GenericNew(AugStore_type, NULL, NULL); + if (!AugStore_singleton) return 0; + Param_type = make_type("Param", expr_context_type, NULL, 0); + if (!Param_type) return 0; + Param_singleton = PyType_GenericNew(Param_type, NULL, NULL); + if (!Param_singleton) return 0; + slice_type = make_type("slice", &AST_type, NULL, 0); + if (!slice_type) return 0; + if (!add_attributes(slice_type, NULL, 0)) return 0; + Slice_type = make_type("Slice", slice_type, Slice_fields, 3); + if (!Slice_type) return 0; + ExtSlice_type = make_type("ExtSlice", slice_type, ExtSlice_fields, 1); + if (!ExtSlice_type) return 0; + Index_type = make_type("Index", slice_type, Index_fields, 1); + if (!Index_type) return 0; + boolop_type = make_type("boolop", &AST_type, NULL, 0); + if (!boolop_type) return 0; + if (!add_attributes(boolop_type, NULL, 0)) return 0; + And_type = make_type("And", boolop_type, NULL, 0); + if (!And_type) return 0; + And_singleton = PyType_GenericNew(And_type, NULL, NULL); + if (!And_singleton) return 0; + Or_type = make_type("Or", boolop_type, NULL, 0); + if (!Or_type) return 0; + Or_singleton = PyType_GenericNew(Or_type, NULL, NULL); + if (!Or_singleton) return 0; + operator_type = make_type("operator", &AST_type, NULL, 0); + if (!operator_type) return 0; + if (!add_attributes(operator_type, NULL, 0)) return 0; + Add_type = make_type("Add", operator_type, NULL, 0); + if (!Add_type) return 0; + Add_singleton = PyType_GenericNew(Add_type, NULL, NULL); + if (!Add_singleton) return 0; + Sub_type = make_type("Sub", operator_type, NULL, 0); + if (!Sub_type) return 0; + Sub_singleton = PyType_GenericNew(Sub_type, NULL, NULL); + if (!Sub_singleton) return 0; + Mult_type = make_type("Mult", operator_type, NULL, 0); + if (!Mult_type) return 0; + Mult_singleton = PyType_GenericNew(Mult_type, NULL, NULL); + if (!Mult_singleton) return 0; + Div_type = make_type("Div", operator_type, NULL, 0); + if (!Div_type) return 0; + Div_singleton = PyType_GenericNew(Div_type, NULL, NULL); + if (!Div_singleton) return 0; + Mod_type = make_type("Mod", operator_type, NULL, 0); + if (!Mod_type) return 0; + Mod_singleton = PyType_GenericNew(Mod_type, NULL, NULL); + if (!Mod_singleton) return 0; + Pow_type = make_type("Pow", operator_type, NULL, 0); + if (!Pow_type) return 0; + Pow_singleton = PyType_GenericNew(Pow_type, NULL, NULL); + if (!Pow_singleton) return 0; + LShift_type = make_type("LShift", operator_type, NULL, 0); + if (!LShift_type) return 0; + LShift_singleton = PyType_GenericNew(LShift_type, NULL, NULL); + if (!LShift_singleton) return 0; + RShift_type = make_type("RShift", operator_type, NULL, 0); + if (!RShift_type) return 0; + RShift_singleton = PyType_GenericNew(RShift_type, NULL, NULL); + if (!RShift_singleton) return 0; + BitOr_type = make_type("BitOr", operator_type, NULL, 0); + if (!BitOr_type) return 0; + BitOr_singleton = PyType_GenericNew(BitOr_type, NULL, NULL); + if (!BitOr_singleton) return 0; + BitXor_type = make_type("BitXor", operator_type, NULL, 0); + if (!BitXor_type) return 0; + BitXor_singleton = PyType_GenericNew(BitXor_type, NULL, NULL); + if (!BitXor_singleton) return 0; + BitAnd_type = make_type("BitAnd", operator_type, NULL, 0); + if (!BitAnd_type) return 0; + BitAnd_singleton = PyType_GenericNew(BitAnd_type, NULL, NULL); + if (!BitAnd_singleton) return 0; + FloorDiv_type = make_type("FloorDiv", operator_type, NULL, 0); + if (!FloorDiv_type) return 0; + FloorDiv_singleton = PyType_GenericNew(FloorDiv_type, NULL, NULL); + if (!FloorDiv_singleton) return 0; + unaryop_type = make_type("unaryop", &AST_type, NULL, 0); + if (!unaryop_type) return 0; + if (!add_attributes(unaryop_type, NULL, 0)) return 0; + Invert_type = make_type("Invert", unaryop_type, NULL, 0); + if (!Invert_type) return 0; + Invert_singleton = PyType_GenericNew(Invert_type, NULL, NULL); + if (!Invert_singleton) return 0; + Not_type = make_type("Not", unaryop_type, NULL, 0); + if (!Not_type) return 0; + Not_singleton = PyType_GenericNew(Not_type, NULL, NULL); + if (!Not_singleton) return 0; + UAdd_type = make_type("UAdd", unaryop_type, NULL, 0); + if (!UAdd_type) return 0; + UAdd_singleton = PyType_GenericNew(UAdd_type, NULL, NULL); + if (!UAdd_singleton) return 0; + USub_type = make_type("USub", unaryop_type, NULL, 0); + if (!USub_type) return 0; + USub_singleton = PyType_GenericNew(USub_type, NULL, NULL); + if (!USub_singleton) return 0; + cmpop_type = make_type("cmpop", &AST_type, NULL, 0); + if (!cmpop_type) return 0; + if (!add_attributes(cmpop_type, NULL, 0)) return 0; + Eq_type = make_type("Eq", cmpop_type, NULL, 0); + if (!Eq_type) return 0; + Eq_singleton = PyType_GenericNew(Eq_type, NULL, NULL); + if (!Eq_singleton) return 0; + NotEq_type = make_type("NotEq", cmpop_type, NULL, 0); + if (!NotEq_type) return 0; + NotEq_singleton = PyType_GenericNew(NotEq_type, NULL, NULL); + if (!NotEq_singleton) return 0; + Lt_type = make_type("Lt", cmpop_type, NULL, 0); + if (!Lt_type) return 0; + Lt_singleton = PyType_GenericNew(Lt_type, NULL, NULL); + if (!Lt_singleton) return 0; + LtE_type = make_type("LtE", cmpop_type, NULL, 0); + if (!LtE_type) return 0; + LtE_singleton = PyType_GenericNew(LtE_type, NULL, NULL); + if (!LtE_singleton) return 0; + Gt_type = make_type("Gt", cmpop_type, NULL, 0); + if (!Gt_type) return 0; + Gt_singleton = PyType_GenericNew(Gt_type, NULL, NULL); + if (!Gt_singleton) return 0; + GtE_type = make_type("GtE", cmpop_type, NULL, 0); + if (!GtE_type) return 0; + GtE_singleton = PyType_GenericNew(GtE_type, NULL, NULL); + if (!GtE_singleton) return 0; + Is_type = make_type("Is", cmpop_type, NULL, 0); + if (!Is_type) return 0; + Is_singleton = PyType_GenericNew(Is_type, NULL, NULL); + if (!Is_singleton) return 0; + IsNot_type = make_type("IsNot", cmpop_type, NULL, 0); + if (!IsNot_type) return 0; + IsNot_singleton = PyType_GenericNew(IsNot_type, NULL, NULL); + if (!IsNot_singleton) return 0; + In_type = make_type("In", cmpop_type, NULL, 0); + if (!In_type) return 0; + In_singleton = PyType_GenericNew(In_type, NULL, NULL); + if (!In_singleton) return 0; + NotIn_type = make_type("NotIn", cmpop_type, NULL, 0); + if (!NotIn_type) return 0; + NotIn_singleton = PyType_GenericNew(NotIn_type, NULL, NULL); + if (!NotIn_singleton) return 0; + comprehension_type = make_type("comprehension", &AST_type, + comprehension_fields, 3); + if (!comprehension_type) return 0; + excepthandler_type = make_type("excepthandler", &AST_type, NULL, 0); + if (!excepthandler_type) return 0; + if (!add_attributes(excepthandler_type, excepthandler_attributes, 2)) + return 0; + ExceptHandler_type = make_type("ExceptHandler", excepthandler_type, + ExceptHandler_fields, 3); + if (!ExceptHandler_type) return 0; + arguments_type = make_type("arguments", &AST_type, arguments_fields, 8); + if (!arguments_type) return 0; + arg_type = make_type("arg", &AST_type, arg_fields, 2); + if (!arg_type) return 0; + keyword_type = make_type("keyword", &AST_type, keyword_fields, 2); + if (!keyword_type) return 0; + alias_type = make_type("alias", &AST_type, alias_fields, 2); + if (!alias_type) return 0; + withitem_type = make_type("withitem", &AST_type, withitem_fields, 2); + if (!withitem_type) return 0; + initialized = 1; + return 1; } static int obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena); @@ -1081,54 +1079,54 @@ mod_ty Module(asdl_seq * body, PyArena *arena) { - mod_ty p; - p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Module_kind; - p->v.Module.body = body; - return p; + mod_ty p; + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Module_kind; + p->v.Module.body = body; + return p; } mod_ty Interactive(asdl_seq * body, PyArena *arena) { - mod_ty p; - p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Interactive_kind; - p->v.Interactive.body = body; - return p; + mod_ty p; + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Interactive_kind; + p->v.Interactive.body = body; + return p; } mod_ty Expression(expr_ty body, PyArena *arena) { - mod_ty p; - if (!body) { - PyErr_SetString(PyExc_ValueError, - "field body is required for Expression"); - return NULL; - } - p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Expression_kind; - p->v.Expression.body = body; - return p; + mod_ty p; + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for Expression"); + return NULL; + } + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Expression_kind; + p->v.Expression.body = body; + return p; } mod_ty Suite(asdl_seq * body, PyArena *arena) { - mod_ty p; - p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Suite_kind; - p->v.Suite.body = body; - return p; + mod_ty p; + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Suite_kind; + p->v.Suite.body = body; + return p; } stmt_ty @@ -1136,29 +1134,29 @@ decorator_list, expr_ty returns, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!name) { - PyErr_SetString(PyExc_ValueError, - "field name is required for FunctionDef"); - return NULL; - } - if (!args) { - PyErr_SetString(PyExc_ValueError, - "field args is required for FunctionDef"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = FunctionDef_kind; - p->v.FunctionDef.name = name; - p->v.FunctionDef.args = args; - p->v.FunctionDef.body = body; - p->v.FunctionDef.decorator_list = decorator_list; - p->v.FunctionDef.returns = returns; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field name is required for FunctionDef"); + return NULL; + } + if (!args) { + PyErr_SetString(PyExc_ValueError, + "field args is required for FunctionDef"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = FunctionDef_kind; + p->v.FunctionDef.name = name; + p->v.FunctionDef.args = args; + p->v.FunctionDef.body = body; + p->v.FunctionDef.decorator_list = decorator_list; + p->v.FunctionDef.returns = returns; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty @@ -1166,1012 +1164,1012 @@ starargs, expr_ty kwargs, asdl_seq * body, asdl_seq * decorator_list, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!name) { - PyErr_SetString(PyExc_ValueError, - "field name is required for ClassDef"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ClassDef_kind; - p->v.ClassDef.name = name; - p->v.ClassDef.bases = bases; - p->v.ClassDef.keywords = keywords; - p->v.ClassDef.starargs = starargs; - p->v.ClassDef.kwargs = kwargs; - p->v.ClassDef.body = body; - p->v.ClassDef.decorator_list = decorator_list; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field name is required for ClassDef"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ClassDef_kind; + p->v.ClassDef.name = name; + p->v.ClassDef.bases = bases; + p->v.ClassDef.keywords = keywords; + p->v.ClassDef.starargs = starargs; + p->v.ClassDef.kwargs = kwargs; + p->v.ClassDef.body = body; + p->v.ClassDef.decorator_list = decorator_list; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Return(expr_ty value, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Return_kind; - p->v.Return.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Return_kind; + p->v.Return.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Delete(asdl_seq * targets, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Delete_kind; - p->v.Delete.targets = targets; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Delete_kind; + p->v.Delete.targets = targets; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Assign(asdl_seq * targets, expr_ty value, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Assign"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Assign_kind; - p->v.Assign.targets = targets; - p->v.Assign.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Assign"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Assign_kind; + p->v.Assign.targets = targets; + p->v.Assign.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!target) { - PyErr_SetString(PyExc_ValueError, - "field target is required for AugAssign"); - return NULL; - } - if (!op) { - PyErr_SetString(PyExc_ValueError, - "field op is required for AugAssign"); - return NULL; - } - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for AugAssign"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = AugAssign_kind; - p->v.AugAssign.target = target; - p->v.AugAssign.op = op; - p->v.AugAssign.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!target) { + PyErr_SetString(PyExc_ValueError, + "field target is required for AugAssign"); + return NULL; + } + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for AugAssign"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for AugAssign"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = AugAssign_kind; + p->v.AugAssign.target = target; + p->v.AugAssign.op = op; + p->v.AugAssign.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!target) { - PyErr_SetString(PyExc_ValueError, - "field target is required for For"); - return NULL; - } - if (!iter) { - PyErr_SetString(PyExc_ValueError, - "field iter is required for For"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = For_kind; - p->v.For.target = target; - p->v.For.iter = iter; - p->v.For.body = body; - p->v.For.orelse = orelse; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!target) { + PyErr_SetString(PyExc_ValueError, + "field target is required for For"); + return NULL; + } + if (!iter) { + PyErr_SetString(PyExc_ValueError, + "field iter is required for For"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = For_kind; + p->v.For.target = target; + p->v.For.iter = iter; + p->v.For.body = body; + p->v.For.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!test) { - PyErr_SetString(PyExc_ValueError, - "field test is required for While"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = While_kind; - p->v.While.test = test; - p->v.While.body = body; - p->v.While.orelse = orelse; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for While"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = While_kind; + p->v.While.test = test; + p->v.While.body = body; + p->v.While.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!test) { - PyErr_SetString(PyExc_ValueError, - "field test is required for If"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = If_kind; - p->v.If.test = test; - p->v.If.body = body; - p->v.If.orelse = orelse; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for If"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = If_kind; + p->v.If.test = test; + p->v.If.body = body; + p->v.If.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty With(asdl_seq * items, asdl_seq * body, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = With_kind; - p->v.With.items = items; - p->v.With.body = body; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = With_kind; + p->v.With.items = items; + p->v.With.body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Raise_kind; - p->v.Raise.exc = exc; - p->v.Raise.cause = cause; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Raise_kind; + p->v.Raise.exc = exc; + p->v.Raise.cause = cause; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Try(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, asdl_seq * finalbody, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Try_kind; - p->v.Try.body = body; - p->v.Try.handlers = handlers; - p->v.Try.orelse = orelse; - p->v.Try.finalbody = finalbody; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Try_kind; + p->v.Try.body = body; + p->v.Try.handlers = handlers; + p->v.Try.orelse = orelse; + p->v.Try.finalbody = finalbody; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!test) { - PyErr_SetString(PyExc_ValueError, - "field test is required for Assert"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Assert_kind; - p->v.Assert.test = test; - p->v.Assert.msg = msg; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for Assert"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Assert_kind; + p->v.Assert.test = test; + p->v.Assert.msg = msg; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Import(asdl_seq * names, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Import_kind; - p->v.Import.names = names; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Import_kind; + p->v.Import.names = names; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty ImportFrom(identifier module, asdl_seq * names, int level, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ImportFrom_kind; - p->v.ImportFrom.module = module; - p->v.ImportFrom.names = names; - p->v.ImportFrom.level = level; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ImportFrom_kind; + p->v.ImportFrom.module = module; + p->v.ImportFrom.names = names; + p->v.ImportFrom.level = level; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Global(asdl_seq * names, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Global_kind; - p->v.Global.names = names; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Global_kind; + p->v.Global.names = names; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Nonlocal(asdl_seq * names, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Nonlocal_kind; - p->v.Nonlocal.names = names; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Nonlocal_kind; + p->v.Nonlocal.names = names; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Expr(expr_ty value, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Expr"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Expr_kind; - p->v.Expr.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Expr"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Expr_kind; + p->v.Expr.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Pass(int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Pass_kind; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Pass_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Break(int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Break_kind; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Break_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Continue(int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Continue_kind; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Continue_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty BoolOp(boolop_ty op, asdl_seq * values, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!op) { - PyErr_SetString(PyExc_ValueError, - "field op is required for BoolOp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = BoolOp_kind; - p->v.BoolOp.op = op; - p->v.BoolOp.values = values; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for BoolOp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = BoolOp_kind; + p->v.BoolOp.op = op; + p->v.BoolOp.values = values; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!left) { - PyErr_SetString(PyExc_ValueError, - "field left is required for BinOp"); - return NULL; - } - if (!op) { - PyErr_SetString(PyExc_ValueError, - "field op is required for BinOp"); - return NULL; - } - if (!right) { - PyErr_SetString(PyExc_ValueError, - "field right is required for BinOp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = BinOp_kind; - p->v.BinOp.left = left; - p->v.BinOp.op = op; - p->v.BinOp.right = right; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!left) { + PyErr_SetString(PyExc_ValueError, + "field left is required for BinOp"); + return NULL; + } + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for BinOp"); + return NULL; + } + if (!right) { + PyErr_SetString(PyExc_ValueError, + "field right is required for BinOp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = BinOp_kind; + p->v.BinOp.left = left; + p->v.BinOp.op = op; + p->v.BinOp.right = right; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!op) { - PyErr_SetString(PyExc_ValueError, - "field op is required for UnaryOp"); - return NULL; - } - if (!operand) { - PyErr_SetString(PyExc_ValueError, - "field operand is required for UnaryOp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = UnaryOp_kind; - p->v.UnaryOp.op = op; - p->v.UnaryOp.operand = operand; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for UnaryOp"); + return NULL; + } + if (!operand) { + PyErr_SetString(PyExc_ValueError, + "field operand is required for UnaryOp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = UnaryOp_kind; + p->v.UnaryOp.op = op; + p->v.UnaryOp.operand = operand; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!args) { - PyErr_SetString(PyExc_ValueError, - "field args is required for Lambda"); - return NULL; - } - if (!body) { - PyErr_SetString(PyExc_ValueError, - "field body is required for Lambda"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Lambda_kind; - p->v.Lambda.args = args; - p->v.Lambda.body = body; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!args) { + PyErr_SetString(PyExc_ValueError, + "field args is required for Lambda"); + return NULL; + } + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for Lambda"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Lambda_kind; + p->v.Lambda.args = args; + p->v.Lambda.body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!test) { - PyErr_SetString(PyExc_ValueError, - "field test is required for IfExp"); - return NULL; - } - if (!body) { - PyErr_SetString(PyExc_ValueError, - "field body is required for IfExp"); - return NULL; - } - if (!orelse) { - PyErr_SetString(PyExc_ValueError, - "field orelse is required for IfExp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = IfExp_kind; - p->v.IfExp.test = test; - p->v.IfExp.body = body; - p->v.IfExp.orelse = orelse; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for IfExp"); + return NULL; + } + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for IfExp"); + return NULL; + } + if (!orelse) { + PyErr_SetString(PyExc_ValueError, + "field orelse is required for IfExp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = IfExp_kind; + p->v.IfExp.test = test; + p->v.IfExp.body = body; + p->v.IfExp.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Dict(asdl_seq * keys, asdl_seq * values, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Dict_kind; - p->v.Dict.keys = keys; - p->v.Dict.values = values; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Dict_kind; + p->v.Dict.keys = keys; + p->v.Dict.values = values; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Set(asdl_seq * elts, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Set_kind; - p->v.Set.elts = elts; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Set_kind; + p->v.Set.elts = elts; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty ListComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!elt) { - PyErr_SetString(PyExc_ValueError, - "field elt is required for ListComp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ListComp_kind; - p->v.ListComp.elt = elt; - p->v.ListComp.generators = generators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!elt) { + PyErr_SetString(PyExc_ValueError, + "field elt is required for ListComp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ListComp_kind; + p->v.ListComp.elt = elt; + p->v.ListComp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty SetComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!elt) { - PyErr_SetString(PyExc_ValueError, - "field elt is required for SetComp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = SetComp_kind; - p->v.SetComp.elt = elt; - p->v.SetComp.generators = generators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!elt) { + PyErr_SetString(PyExc_ValueError, + "field elt is required for SetComp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = SetComp_kind; + p->v.SetComp.elt = elt; + p->v.SetComp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!key) { - PyErr_SetString(PyExc_ValueError, - "field key is required for DictComp"); - return NULL; - } - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for DictComp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = DictComp_kind; - p->v.DictComp.key = key; - p->v.DictComp.value = value; - p->v.DictComp.generators = generators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!key) { + PyErr_SetString(PyExc_ValueError, + "field key is required for DictComp"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for DictComp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = DictComp_kind; + p->v.DictComp.key = key; + p->v.DictComp.value = value; + p->v.DictComp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!elt) { - PyErr_SetString(PyExc_ValueError, - "field elt is required for GeneratorExp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = GeneratorExp_kind; - p->v.GeneratorExp.elt = elt; - p->v.GeneratorExp.generators = generators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!elt) { + PyErr_SetString(PyExc_ValueError, + "field elt is required for GeneratorExp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = GeneratorExp_kind; + p->v.GeneratorExp.elt = elt; + p->v.GeneratorExp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Yield(expr_ty value, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Yield_kind; - p->v.Yield.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Yield_kind; + p->v.Yield.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty YieldFrom(expr_ty value, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for YieldFrom"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = YieldFrom_kind; - p->v.YieldFrom.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for YieldFrom"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = YieldFrom_kind; + p->v.YieldFrom.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!left) { - PyErr_SetString(PyExc_ValueError, - "field left is required for Compare"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Compare_kind; - p->v.Compare.left = left; - p->v.Compare.ops = ops; - p->v.Compare.comparators = comparators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!left) { + PyErr_SetString(PyExc_ValueError, + "field left is required for Compare"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Compare_kind; + p->v.Compare.left = left; + p->v.Compare.ops = ops; + p->v.Compare.comparators = comparators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, expr_ty starargs, expr_ty kwargs, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!func) { - PyErr_SetString(PyExc_ValueError, - "field func is required for Call"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Call_kind; - p->v.Call.func = func; - p->v.Call.args = args; - p->v.Call.keywords = keywords; - p->v.Call.starargs = starargs; - p->v.Call.kwargs = kwargs; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!func) { + PyErr_SetString(PyExc_ValueError, + "field func is required for Call"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Call_kind; + p->v.Call.func = func; + p->v.Call.args = args; + p->v.Call.keywords = keywords; + p->v.Call.starargs = starargs; + p->v.Call.kwargs = kwargs; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Num(object n, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!n) { - PyErr_SetString(PyExc_ValueError, - "field n is required for Num"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Num_kind; - p->v.Num.n = n; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!n) { + PyErr_SetString(PyExc_ValueError, + "field n is required for Num"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Num_kind; + p->v.Num.n = n; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Str(string s, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!s) { - PyErr_SetString(PyExc_ValueError, - "field s is required for Str"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Str_kind; - p->v.Str.s = s; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!s) { + PyErr_SetString(PyExc_ValueError, + "field s is required for Str"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Str_kind; + p->v.Str.s = s; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Bytes(bytes s, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!s) { - PyErr_SetString(PyExc_ValueError, - "field s is required for Bytes"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Bytes_kind; - p->v.Bytes.s = s; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!s) { + PyErr_SetString(PyExc_ValueError, + "field s is required for Bytes"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Bytes_kind; + p->v.Bytes.s = s; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Ellipsis(int lineno, int col_offset, PyArena *arena) { - expr_ty p; - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Ellipsis_kind; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Ellipsis_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Attribute"); - return NULL; - } - if (!attr) { - PyErr_SetString(PyExc_ValueError, - "field attr is required for Attribute"); - return NULL; - } - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Attribute"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Attribute_kind; - p->v.Attribute.value = value; - p->v.Attribute.attr = attr; - p->v.Attribute.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Attribute"); + return NULL; + } + if (!attr) { + PyErr_SetString(PyExc_ValueError, + "field attr is required for Attribute"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Attribute"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Attribute_kind; + p->v.Attribute.value = value; + p->v.Attribute.attr = attr; + p->v.Attribute.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Subscript"); - return NULL; - } - if (!slice) { - PyErr_SetString(PyExc_ValueError, - "field slice is required for Subscript"); - return NULL; - } - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Subscript"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Subscript_kind; - p->v.Subscript.value = value; - p->v.Subscript.slice = slice; - p->v.Subscript.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Subscript"); + return NULL; + } + if (!slice) { + PyErr_SetString(PyExc_ValueError, + "field slice is required for Subscript"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Subscript"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Subscript_kind; + p->v.Subscript.value = value; + p->v.Subscript.slice = slice; + p->v.Subscript.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Starred(expr_ty value, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Starred"); - return NULL; - } - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Starred"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Starred_kind; - p->v.Starred.value = value; - p->v.Starred.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Starred"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Starred"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Starred_kind; + p->v.Starred.value = value; + p->v.Starred.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Name(identifier id, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!id) { - PyErr_SetString(PyExc_ValueError, - "field id is required for Name"); - return NULL; - } - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Name"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Name_kind; - p->v.Name.id = id; - p->v.Name.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!id) { + PyErr_SetString(PyExc_ValueError, + "field id is required for Name"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Name"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Name_kind; + p->v.Name.id = id; + p->v.Name.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty List(asdl_seq * elts, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for List"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = List_kind; - p->v.List.elts = elts; - p->v.List.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for List"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = List_kind; + p->v.List.elts = elts; + p->v.List.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Tuple"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Tuple_kind; - p->v.Tuple.elts = elts; - p->v.Tuple.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Tuple"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Tuple_kind; + p->v.Tuple.elts = elts; + p->v.Tuple.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } slice_ty Slice(expr_ty lower, expr_ty upper, expr_ty step, PyArena *arena) { - slice_ty p; - p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Slice_kind; - p->v.Slice.lower = lower; - p->v.Slice.upper = upper; - p->v.Slice.step = step; - return p; + slice_ty p; + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Slice_kind; + p->v.Slice.lower = lower; + p->v.Slice.upper = upper; + p->v.Slice.step = step; + return p; } slice_ty ExtSlice(asdl_seq * dims, PyArena *arena) { - slice_ty p; - p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ExtSlice_kind; - p->v.ExtSlice.dims = dims; - return p; + slice_ty p; + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ExtSlice_kind; + p->v.ExtSlice.dims = dims; + return p; } slice_ty Index(expr_ty value, PyArena *arena) { - slice_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Index"); - return NULL; - } - p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Index_kind; - p->v.Index.value = value; - return p; + slice_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Index"); + return NULL; + } + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Index_kind; + p->v.Index.value = value; + return p; } comprehension_ty comprehension(expr_ty target, expr_ty iter, asdl_seq * ifs, PyArena *arena) { - comprehension_ty p; - if (!target) { - PyErr_SetString(PyExc_ValueError, - "field target is required for comprehension"); - return NULL; - } - if (!iter) { - PyErr_SetString(PyExc_ValueError, - "field iter is required for comprehension"); - return NULL; - } - p = (comprehension_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->target = target; - p->iter = iter; - p->ifs = ifs; - return p; + comprehension_ty p; + if (!target) { + PyErr_SetString(PyExc_ValueError, + "field target is required for comprehension"); + return NULL; + } + if (!iter) { + PyErr_SetString(PyExc_ValueError, + "field iter is required for comprehension"); + return NULL; + } + p = (comprehension_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->target = target; + p->iter = iter; + p->ifs = ifs; + return p; } excepthandler_ty ExceptHandler(expr_ty type, identifier name, asdl_seq * body, int lineno, int col_offset, PyArena *arena) { - excepthandler_ty p; - p = (excepthandler_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ExceptHandler_kind; - p->v.ExceptHandler.type = type; - p->v.ExceptHandler.name = name; - p->v.ExceptHandler.body = body; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + excepthandler_ty p; + p = (excepthandler_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ExceptHandler_kind; + p->v.ExceptHandler.type = type; + p->v.ExceptHandler.name = name; + p->v.ExceptHandler.body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } arguments_ty @@ -2179,4726 +2177,4714 @@ asdl_seq * kwonlyargs, identifier kwarg, expr_ty kwargannotation, asdl_seq * defaults, asdl_seq * kw_defaults, PyArena *arena) { - arguments_ty p; - p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->args = args; - p->vararg = vararg; - p->varargannotation = varargannotation; - p->kwonlyargs = kwonlyargs; - p->kwarg = kwarg; - p->kwargannotation = kwargannotation; - p->defaults = defaults; - p->kw_defaults = kw_defaults; - return p; + arguments_ty p; + p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->args = args; + p->vararg = vararg; + p->varargannotation = varargannotation; + p->kwonlyargs = kwonlyargs; + p->kwarg = kwarg; + p->kwargannotation = kwargannotation; + p->defaults = defaults; + p->kw_defaults = kw_defaults; + return p; } arg_ty arg(identifier arg, expr_ty annotation, PyArena *arena) { - arg_ty p; - if (!arg) { - PyErr_SetString(PyExc_ValueError, - "field arg is required for arg"); - return NULL; - } - p = (arg_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->arg = arg; - p->annotation = annotation; - return p; + arg_ty p; + if (!arg) { + PyErr_SetString(PyExc_ValueError, + "field arg is required for arg"); + return NULL; + } + p = (arg_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->arg = arg; + p->annotation = annotation; + return p; } keyword_ty keyword(identifier arg, expr_ty value, PyArena *arena) { - keyword_ty p; - if (!arg) { - PyErr_SetString(PyExc_ValueError, - "field arg is required for keyword"); - return NULL; - } - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for keyword"); - return NULL; - } - p = (keyword_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->arg = arg; - p->value = value; - return p; + keyword_ty p; + if (!arg) { + PyErr_SetString(PyExc_ValueError, + "field arg is required for keyword"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for keyword"); + return NULL; + } + p = (keyword_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->arg = arg; + p->value = value; + return p; } alias_ty alias(identifier name, identifier asname, PyArena *arena) { - alias_ty p; - if (!name) { - PyErr_SetString(PyExc_ValueError, - "field name is required for alias"); - return NULL; - } - p = (alias_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->name = name; - p->asname = asname; - return p; + alias_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field name is required for alias"); + return NULL; + } + p = (alias_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->name = name; + p->asname = asname; + return p; } withitem_ty withitem(expr_ty context_expr, expr_ty optional_vars, PyArena *arena) { - withitem_ty p; - if (!context_expr) { - PyErr_SetString(PyExc_ValueError, - "field context_expr is required for withitem"); - return NULL; - } - p = (withitem_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->context_expr = context_expr; - p->optional_vars = optional_vars; - return p; + withitem_ty p; + if (!context_expr) { + PyErr_SetString(PyExc_ValueError, + "field context_expr is required for withitem"); + return NULL; + } + p = (withitem_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->context_expr = context_expr; + p->optional_vars = optional_vars; + return p; } PyObject* ast2obj_mod(void* _o) { - mod_ty o = (mod_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - switch (o->kind) { - case Module_kind: - result = PyType_GenericNew(Module_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Module.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Interactive_kind: - result = PyType_GenericNew(Interactive_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Interactive.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Expression_kind: - result = PyType_GenericNew(Expression_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Expression.body); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Suite_kind: - result = PyType_GenericNew(Suite_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Suite.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - } - return result; + mod_ty o = (mod_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case Module_kind: + result = PyType_GenericNew(Module_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Module.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Interactive_kind: + result = PyType_GenericNew(Interactive_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Interactive.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Expression_kind: + result = PyType_GenericNew(Expression_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Expression.body); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Suite_kind: + result = PyType_GenericNew(Suite_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Suite.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_stmt(void* _o) { - stmt_ty o = (stmt_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - switch (o->kind) { - case FunctionDef_kind: - result = PyType_GenericNew(FunctionDef_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_identifier(o->v.FunctionDef.name); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_arguments(o->v.FunctionDef.args); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.FunctionDef.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.FunctionDef.decorator_list, - ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_decorator_list, value) == - -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.FunctionDef.returns); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_returns, value) == -1) - goto failed; - Py_DECREF(value); - break; - case ClassDef_kind: - result = PyType_GenericNew(ClassDef_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_identifier(o->v.ClassDef.name); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ClassDef.bases, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_bases, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ClassDef.keywords, ast2obj_keyword); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.ClassDef.starargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.ClassDef.kwargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ClassDef.decorator_list, - ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_decorator_list, value) == - -1) - goto failed; - Py_DECREF(value); - break; - case Return_kind: - result = PyType_GenericNew(Return_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Return.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Delete_kind: - result = PyType_GenericNew(Delete_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Delete.targets, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_targets, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Assign_kind: - result = PyType_GenericNew(Assign_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Assign.targets, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_targets, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Assign.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case AugAssign_kind: - result = PyType_GenericNew(AugAssign_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.AugAssign.target); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_operator(o->v.AugAssign.op); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.AugAssign.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case For_kind: - result = PyType_GenericNew(For_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.For.target); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.For.iter); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_iter, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.For.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.For.orelse, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - break; - case While_kind: - result = PyType_GenericNew(While_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.While.test); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.While.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.While.orelse, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - break; - case If_kind: - result = PyType_GenericNew(If_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.If.test); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.If.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.If.orelse, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - break; - case With_kind: - result = PyType_GenericNew(With_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.With.items, ast2obj_withitem); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_items, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.With.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Raise_kind: - result = PyType_GenericNew(Raise_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Raise.exc); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_exc, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Raise.cause); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_cause, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Try_kind: - result = PyType_GenericNew(Try_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Try.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Try.handlers, ast2obj_excepthandler); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_handlers, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Try.orelse, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Try.finalbody, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_finalbody, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Assert_kind: - result = PyType_GenericNew(Assert_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Assert.test); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Assert.msg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_msg, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Import_kind: - result = PyType_GenericNew(Import_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Import.names, ast2obj_alias); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) - goto failed; - Py_DECREF(value); - break; - case ImportFrom_kind: - result = PyType_GenericNew(ImportFrom_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_identifier(o->v.ImportFrom.module); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_module, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ImportFrom.names, ast2obj_alias); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_int(o->v.ImportFrom.level); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_level, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Global_kind: - result = PyType_GenericNew(Global_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Global.names, ast2obj_identifier); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Nonlocal_kind: - result = PyType_GenericNew(Nonlocal_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Nonlocal.names, ast2obj_identifier); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Expr_kind: - result = PyType_GenericNew(Expr_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Expr.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Pass_kind: - result = PyType_GenericNew(Pass_type, NULL, NULL); - if (!result) goto failed; - break; - case Break_kind: - result = PyType_GenericNew(Break_type, NULL, NULL); - if (!result) goto failed; - break; - case Continue_kind: - result = PyType_GenericNew(Continue_type, NULL, NULL); - if (!result) goto failed; - break; - } - value = ast2obj_int(o->lineno); + stmt_ty o = (stmt_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case FunctionDef_kind: + result = PyType_GenericNew(FunctionDef_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.FunctionDef.name); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) + goto failed; Py_DECREF(value); - value = ast2obj_int(o->col_offset); + value = ast2obj_arguments(o->v.FunctionDef.args); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) + goto failed; Py_DECREF(value); - return result; + value = ast2obj_list(o->v.FunctionDef.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.FunctionDef.decorator_list, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_decorator_list, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.FunctionDef.returns); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_returns, value) == -1) + goto failed; + Py_DECREF(value); + break; + case ClassDef_kind: + result = PyType_GenericNew(ClassDef_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.ClassDef.name); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.bases, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_bases, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.keywords, ast2obj_keyword); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.ClassDef.starargs); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.ClassDef.kwargs); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.decorator_list, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_decorator_list, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Return_kind: + result = PyType_GenericNew(Return_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Return.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Delete_kind: + result = PyType_GenericNew(Delete_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Delete.targets, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_targets, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Assign_kind: + result = PyType_GenericNew(Assign_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Assign.targets, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_targets, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Assign.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case AugAssign_kind: + result = PyType_GenericNew(AugAssign_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.AugAssign.target); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_operator(o->v.AugAssign.op); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.AugAssign.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case For_kind: + result = PyType_GenericNew(For_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.For.target); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.For.iter); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_iter, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.For.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.For.orelse, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + break; + case While_kind: + result = PyType_GenericNew(While_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.While.test); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.While.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.While.orelse, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + break; + case If_kind: + result = PyType_GenericNew(If_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.If.test); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.If.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.If.orelse, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + break; + case With_kind: + result = PyType_GenericNew(With_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.With.items, ast2obj_withitem); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_items, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.With.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Raise_kind: + result = PyType_GenericNew(Raise_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Raise.exc); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_exc, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Raise.cause); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_cause, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Try_kind: + result = PyType_GenericNew(Try_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Try.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Try.handlers, ast2obj_excepthandler); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_handlers, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Try.orelse, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Try.finalbody, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_finalbody, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Assert_kind: + result = PyType_GenericNew(Assert_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Assert.test); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Assert.msg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_msg, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Import_kind: + result = PyType_GenericNew(Import_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Import.names, ast2obj_alias); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) + goto failed; + Py_DECREF(value); + break; + case ImportFrom_kind: + result = PyType_GenericNew(ImportFrom_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.ImportFrom.module); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_module, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ImportFrom.names, ast2obj_alias); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->v.ImportFrom.level); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_level, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Global_kind: + result = PyType_GenericNew(Global_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Global.names, ast2obj_identifier); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Nonlocal_kind: + result = PyType_GenericNew(Nonlocal_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Nonlocal.names, ast2obj_identifier); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Expr_kind: + result = PyType_GenericNew(Expr_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Expr.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Pass_kind: + result = PyType_GenericNew(Pass_type, NULL, NULL); + if (!result) goto failed; + break; + case Break_kind: + result = PyType_GenericNew(Break_type, NULL, NULL); + if (!result) goto failed; + break; + case Continue_kind: + result = PyType_GenericNew(Continue_type, NULL, NULL); + if (!result) goto failed; + break; + } + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_expr(void* _o) { - expr_ty o = (expr_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; + expr_ty o = (expr_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case BoolOp_kind: + result = PyType_GenericNew(BoolOp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_boolop(o->v.BoolOp.op); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.BoolOp.values, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_values, value) == -1) + goto failed; + Py_DECREF(value); + break; + case BinOp_kind: + result = PyType_GenericNew(BinOp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.BinOp.left); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_left, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_operator(o->v.BinOp.op); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.BinOp.right); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_right, value) == -1) + goto failed; + Py_DECREF(value); + break; + case UnaryOp_kind: + result = PyType_GenericNew(UnaryOp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_unaryop(o->v.UnaryOp.op); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.UnaryOp.operand); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_operand, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Lambda_kind: + result = PyType_GenericNew(Lambda_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_arguments(o->v.Lambda.args); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Lambda.body); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case IfExp_kind: + result = PyType_GenericNew(IfExp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.IfExp.test); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.IfExp.body); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.IfExp.orelse); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Dict_kind: + result = PyType_GenericNew(Dict_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Dict.keys, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_keys, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Dict.values, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_values, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Set_kind: + result = PyType_GenericNew(Set_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Set.elts, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) + goto failed; + Py_DECREF(value); + break; + case ListComp_kind: + result = PyType_GenericNew(ListComp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.ListComp.elt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ListComp.generators, ast2obj_comprehension); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) + goto failed; + Py_DECREF(value); + break; + case SetComp_kind: + result = PyType_GenericNew(SetComp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.SetComp.elt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.SetComp.generators, ast2obj_comprehension); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) + goto failed; + Py_DECREF(value); + break; + case DictComp_kind: + result = PyType_GenericNew(DictComp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.DictComp.key); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_key, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.DictComp.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.DictComp.generators, ast2obj_comprehension); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) + goto failed; + Py_DECREF(value); + break; + case GeneratorExp_kind: + result = PyType_GenericNew(GeneratorExp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.GeneratorExp.elt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.GeneratorExp.generators, + ast2obj_comprehension); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Yield_kind: + result = PyType_GenericNew(Yield_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Yield.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case YieldFrom_kind: + result = PyType_GenericNew(YieldFrom_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.YieldFrom.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Compare_kind: + result = PyType_GenericNew(Compare_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Compare.left); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_left, value) == -1) + goto failed; + Py_DECREF(value); + { + Py_ssize_t i, n = asdl_seq_LEN(o->v.Compare.ops); + value = PyList_New(n); + if (!value) goto failed; + for(i = 0; i < n; i++) + PyList_SET_ITEM(value, i, ast2obj_cmpop((cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i))); } - - switch (o->kind) { - case BoolOp_kind: - result = PyType_GenericNew(BoolOp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_boolop(o->v.BoolOp.op); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.BoolOp.values, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_values, value) == -1) - goto failed; - Py_DECREF(value); - break; - case BinOp_kind: - result = PyType_GenericNew(BinOp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.BinOp.left); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_left, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_operator(o->v.BinOp.op); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.BinOp.right); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_right, value) == -1) - goto failed; - Py_DECREF(value); - break; - case UnaryOp_kind: - result = PyType_GenericNew(UnaryOp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_unaryop(o->v.UnaryOp.op); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.UnaryOp.operand); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_operand, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Lambda_kind: - result = PyType_GenericNew(Lambda_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_arguments(o->v.Lambda.args); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Lambda.body); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case IfExp_kind: - result = PyType_GenericNew(IfExp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.IfExp.test); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.IfExp.body); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.IfExp.orelse); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Dict_kind: - result = PyType_GenericNew(Dict_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Dict.keys, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_keys, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Dict.values, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_values, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Set_kind: - result = PyType_GenericNew(Set_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Set.elts, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) - goto failed; - Py_DECREF(value); - break; - case ListComp_kind: - result = PyType_GenericNew(ListComp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.ListComp.elt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ListComp.generators, - ast2obj_comprehension); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case SetComp_kind: - result = PyType_GenericNew(SetComp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.SetComp.elt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.SetComp.generators, - ast2obj_comprehension); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case DictComp_kind: - result = PyType_GenericNew(DictComp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.DictComp.key); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_key, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.DictComp.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.DictComp.generators, - ast2obj_comprehension); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case GeneratorExp_kind: - result = PyType_GenericNew(GeneratorExp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.GeneratorExp.elt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.GeneratorExp.generators, - ast2obj_comprehension); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Yield_kind: - result = PyType_GenericNew(Yield_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Yield.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case YieldFrom_kind: - result = PyType_GenericNew(YieldFrom_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.YieldFrom.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Compare_kind: - result = PyType_GenericNew(Compare_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Compare.left); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_left, value) == -1) - goto failed; - Py_DECREF(value); - { - Py_ssize_t i, n = asdl_seq_LEN(o->v.Compare.ops); - value = PyList_New(n); - if (!value) goto failed; - for(i = 0; i < n; i++) - PyList_SET_ITEM(value, i, ast2obj_cmpop((cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i))); - } - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ops, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Compare.comparators, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_comparators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Call_kind: - result = PyType_GenericNew(Call_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Call.func); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_func, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Call.args, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Call.keywords, ast2obj_keyword); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Call.starargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Call.kwargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Num_kind: - result = PyType_GenericNew(Num_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_object(o->v.Num.n); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_n, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Str_kind: - result = PyType_GenericNew(Str_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_string(o->v.Str.s); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_s, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Bytes_kind: - result = PyType_GenericNew(Bytes_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_bytes(o->v.Bytes.s); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_s, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Ellipsis_kind: - result = PyType_GenericNew(Ellipsis_type, NULL, NULL); - if (!result) goto failed; - break; - case Attribute_kind: - result = PyType_GenericNew(Attribute_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Attribute.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_identifier(o->v.Attribute.attr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_attr, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Attribute.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Subscript_kind: - result = PyType_GenericNew(Subscript_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Subscript.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_slice(o->v.Subscript.slice); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_slice, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Subscript.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Starred_kind: - result = PyType_GenericNew(Starred_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Starred.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Starred.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Name_kind: - result = PyType_GenericNew(Name_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_identifier(o->v.Name.id); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_id, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Name.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case List_kind: - result = PyType_GenericNew(List_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.List.elts, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.List.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Tuple_kind: - result = PyType_GenericNew(Tuple_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Tuple.elts, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Tuple.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - } - value = ast2obj_int(o->lineno); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_ops, value) == -1) + goto failed; Py_DECREF(value); - value = ast2obj_int(o->col_offset); + value = ast2obj_list(o->v.Compare.comparators, ast2obj_expr); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_comparators, value) == -1) + goto failed; Py_DECREF(value); - return result; + break; + case Call_kind: + result = PyType_GenericNew(Call_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Call.func); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_func, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Call.args, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Call.keywords, ast2obj_keyword); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Call.starargs); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Call.kwargs); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Num_kind: + result = PyType_GenericNew(Num_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_object(o->v.Num.n); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_n, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Str_kind: + result = PyType_GenericNew(Str_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_string(o->v.Str.s); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_s, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Bytes_kind: + result = PyType_GenericNew(Bytes_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_bytes(o->v.Bytes.s); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_s, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Ellipsis_kind: + result = PyType_GenericNew(Ellipsis_type, NULL, NULL); + if (!result) goto failed; + break; + case Attribute_kind: + result = PyType_GenericNew(Attribute_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Attribute.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->v.Attribute.attr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_attr, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Attribute.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Subscript_kind: + result = PyType_GenericNew(Subscript_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Subscript.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_slice(o->v.Subscript.slice); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_slice, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Subscript.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Starred_kind: + result = PyType_GenericNew(Starred_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Starred.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Starred.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Name_kind: + result = PyType_GenericNew(Name_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.Name.id); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_id, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Name.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case List_kind: + result = PyType_GenericNew(List_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.List.elts, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.List.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Tuple_kind: + result = PyType_GenericNew(Tuple_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Tuple.elts, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Tuple.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_expr_context(expr_context_ty o) { - switch(o) { - case Load: - Py_INCREF(Load_singleton); - return Load_singleton; - case Store: - Py_INCREF(Store_singleton); - return Store_singleton; - case Del: - Py_INCREF(Del_singleton); - return Del_singleton; - case AugLoad: - Py_INCREF(AugLoad_singleton); - return AugLoad_singleton; - case AugStore: - Py_INCREF(AugStore_singleton); - return AugStore_singleton; - case Param: - Py_INCREF(Param_singleton); - return Param_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown expr_context found"); - return NULL; - } + switch(o) { + case Load: + Py_INCREF(Load_singleton); + return Load_singleton; + case Store: + Py_INCREF(Store_singleton); + return Store_singleton; + case Del: + Py_INCREF(Del_singleton); + return Del_singleton; + case AugLoad: + Py_INCREF(AugLoad_singleton); + return AugLoad_singleton; + case AugStore: + Py_INCREF(AugStore_singleton); + return AugStore_singleton; + case Param: + Py_INCREF(Param_singleton); + return Param_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown expr_context found"); + return NULL; + } } PyObject* ast2obj_slice(void* _o) { - slice_ty o = (slice_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - switch (o->kind) { - case Slice_kind: - result = PyType_GenericNew(Slice_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Slice.lower); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_lower, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Slice.upper); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_upper, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Slice.step); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_step, value) == -1) - goto failed; - Py_DECREF(value); - break; - case ExtSlice_kind: - result = PyType_GenericNew(ExtSlice_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.ExtSlice.dims, ast2obj_slice); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_dims, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Index_kind: - result = PyType_GenericNew(Index_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Index.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - } - return result; + slice_ty o = (slice_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case Slice_kind: + result = PyType_GenericNew(Slice_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Slice.lower); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_lower, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Slice.upper); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_upper, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Slice.step); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_step, value) == -1) + goto failed; + Py_DECREF(value); + break; + case ExtSlice_kind: + result = PyType_GenericNew(ExtSlice_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.ExtSlice.dims, ast2obj_slice); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_dims, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Index_kind: + result = PyType_GenericNew(Index_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Index.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_boolop(boolop_ty o) { - switch(o) { - case And: - Py_INCREF(And_singleton); - return And_singleton; - case Or: - Py_INCREF(Or_singleton); - return Or_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown boolop found"); - return NULL; - } + switch(o) { + case And: + Py_INCREF(And_singleton); + return And_singleton; + case Or: + Py_INCREF(Or_singleton); + return Or_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown boolop found"); + return NULL; + } } PyObject* ast2obj_operator(operator_ty o) { - switch(o) { - case Add: - Py_INCREF(Add_singleton); - return Add_singleton; - case Sub: - Py_INCREF(Sub_singleton); - return Sub_singleton; - case Mult: - Py_INCREF(Mult_singleton); - return Mult_singleton; - case Div: - Py_INCREF(Div_singleton); - return Div_singleton; - case Mod: - Py_INCREF(Mod_singleton); - return Mod_singleton; - case Pow: - Py_INCREF(Pow_singleton); - return Pow_singleton; - case LShift: - Py_INCREF(LShift_singleton); - return LShift_singleton; - case RShift: - Py_INCREF(RShift_singleton); - return RShift_singleton; - case BitOr: - Py_INCREF(BitOr_singleton); - return BitOr_singleton; - case BitXor: - Py_INCREF(BitXor_singleton); - return BitXor_singleton; - case BitAnd: - Py_INCREF(BitAnd_singleton); - return BitAnd_singleton; - case FloorDiv: - Py_INCREF(FloorDiv_singleton); - return FloorDiv_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown operator found"); - return NULL; - } + switch(o) { + case Add: + Py_INCREF(Add_singleton); + return Add_singleton; + case Sub: + Py_INCREF(Sub_singleton); + return Sub_singleton; + case Mult: + Py_INCREF(Mult_singleton); + return Mult_singleton; + case Div: + Py_INCREF(Div_singleton); + return Div_singleton; + case Mod: + Py_INCREF(Mod_singleton); + return Mod_singleton; + case Pow: + Py_INCREF(Pow_singleton); + return Pow_singleton; + case LShift: + Py_INCREF(LShift_singleton); + return LShift_singleton; + case RShift: + Py_INCREF(RShift_singleton); + return RShift_singleton; + case BitOr: + Py_INCREF(BitOr_singleton); + return BitOr_singleton; + case BitXor: + Py_INCREF(BitXor_singleton); + return BitXor_singleton; + case BitAnd: + Py_INCREF(BitAnd_singleton); + return BitAnd_singleton; + case FloorDiv: + Py_INCREF(FloorDiv_singleton); + return FloorDiv_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown operator found"); + return NULL; + } } PyObject* ast2obj_unaryop(unaryop_ty o) { - switch(o) { - case Invert: - Py_INCREF(Invert_singleton); - return Invert_singleton; - case Not: - Py_INCREF(Not_singleton); - return Not_singleton; - case UAdd: - Py_INCREF(UAdd_singleton); - return UAdd_singleton; - case USub: - Py_INCREF(USub_singleton); - return USub_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown unaryop found"); - return NULL; - } + switch(o) { + case Invert: + Py_INCREF(Invert_singleton); + return Invert_singleton; + case Not: + Py_INCREF(Not_singleton); + return Not_singleton; + case UAdd: + Py_INCREF(UAdd_singleton); + return UAdd_singleton; + case USub: + Py_INCREF(USub_singleton); + return USub_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown unaryop found"); + return NULL; + } } PyObject* ast2obj_cmpop(cmpop_ty o) { - switch(o) { - case Eq: - Py_INCREF(Eq_singleton); - return Eq_singleton; - case NotEq: - Py_INCREF(NotEq_singleton); - return NotEq_singleton; - case Lt: - Py_INCREF(Lt_singleton); - return Lt_singleton; - case LtE: - Py_INCREF(LtE_singleton); - return LtE_singleton; - case Gt: - Py_INCREF(Gt_singleton); - return Gt_singleton; - case GtE: - Py_INCREF(GtE_singleton); - return GtE_singleton; - case Is: - Py_INCREF(Is_singleton); - return Is_singleton; - case IsNot: - Py_INCREF(IsNot_singleton); - return IsNot_singleton; - case In: - Py_INCREF(In_singleton); - return In_singleton; - case NotIn: - Py_INCREF(NotIn_singleton); - return NotIn_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown cmpop found"); - return NULL; - } + switch(o) { + case Eq: + Py_INCREF(Eq_singleton); + return Eq_singleton; + case NotEq: + Py_INCREF(NotEq_singleton); + return NotEq_singleton; + case Lt: + Py_INCREF(Lt_singleton); + return Lt_singleton; + case LtE: + Py_INCREF(LtE_singleton); + return LtE_singleton; + case Gt: + Py_INCREF(Gt_singleton); + return Gt_singleton; + case GtE: + Py_INCREF(GtE_singleton); + return GtE_singleton; + case Is: + Py_INCREF(Is_singleton); + return Is_singleton; + case IsNot: + Py_INCREF(IsNot_singleton); + return IsNot_singleton; + case In: + Py_INCREF(In_singleton); + return In_singleton; + case NotIn: + Py_INCREF(NotIn_singleton); + return NotIn_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown cmpop found"); + return NULL; + } } PyObject* ast2obj_comprehension(void* _o) { - comprehension_ty o = (comprehension_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(comprehension_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_expr(o->target); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->iter); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_iter, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->ifs, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ifs, value) == -1) - goto failed; - Py_DECREF(value); - return result; + comprehension_ty o = (comprehension_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(comprehension_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_expr(o->target); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->iter); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_iter, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->ifs, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ifs, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_excepthandler(void* _o) { - excepthandler_ty o = (excepthandler_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - switch (o->kind) { - case ExceptHandler_kind: - result = PyType_GenericNew(ExceptHandler_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.ExceptHandler.type); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_type, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_identifier(o->v.ExceptHandler.name); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ExceptHandler.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - } - value = ast2obj_int(o->lineno); + excepthandler_ty o = (excepthandler_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case ExceptHandler_kind: + result = PyType_GenericNew(ExceptHandler_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.ExceptHandler.type); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_type, value) == -1) + goto failed; Py_DECREF(value); - value = ast2obj_int(o->col_offset); + value = ast2obj_identifier(o->v.ExceptHandler.name); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) + goto failed; Py_DECREF(value); - return result; + value = ast2obj_list(o->v.ExceptHandler.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_arguments(void* _o) { - arguments_ty o = (arguments_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(arguments_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_list(o->args, ast2obj_arg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_identifier(o->vararg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_vararg, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->varargannotation); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_varargannotation, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->kwonlyargs, ast2obj_arg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwonlyargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_identifier(o->kwarg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwarg, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->kwargannotation); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwargannotation, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->defaults, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_defaults, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->kw_defaults, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kw_defaults, value) == -1) - goto failed; - Py_DECREF(value); - return result; + arguments_ty o = (arguments_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(arguments_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_list(o->args, ast2obj_arg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->vararg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_vararg, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->varargannotation); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_varargannotation, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->kwonlyargs, ast2obj_arg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kwonlyargs, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->kwarg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kwarg, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->kwargannotation); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kwargannotation, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->defaults, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_defaults, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->kw_defaults, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kw_defaults, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_arg(void* _o) { - arg_ty o = (arg_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(arg_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_identifier(o->arg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_arg, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->annotation); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_annotation, value) == -1) - goto failed; - Py_DECREF(value); - return result; + arg_ty o = (arg_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(arg_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_identifier(o->arg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_arg, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->annotation); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_annotation, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_keyword(void* _o) { - keyword_ty o = (keyword_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(keyword_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_identifier(o->arg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_arg, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - return result; + keyword_ty o = (keyword_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(keyword_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_identifier(o->arg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_arg, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_alias(void* _o) { - alias_ty o = (alias_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(alias_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_identifier(o->name); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_identifier(o->asname); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_asname, value) == -1) - goto failed; - Py_DECREF(value); - return result; + alias_ty o = (alias_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(alias_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_identifier(o->name); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->asname); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_asname, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_withitem(void* _o) { - withitem_ty o = (withitem_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(withitem_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_expr(o->context_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_context_expr, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->optional_vars); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_optional_vars, value) == -1) - goto failed; - Py_DECREF(value); - return result; + withitem_ty o = (withitem_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(withitem_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_expr(o->context_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_context_expr, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->optional_vars); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_optional_vars, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } int obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Module_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* body; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Module field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Module_type); - if (isinstance == -1) { - return 1; + *out = Module(body, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Interactive_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* body; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Interactive field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive"); + return 1; } - if (isinstance) { - asdl_seq* body; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Module field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module"); - return 1; - } - *out = Module(body, arena); - if (*out == NULL) goto failed; - return 0; + *out = Interactive(body, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Expression_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty body; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &body, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Interactive_type); - if (isinstance == -1) { - return 1; + *out = Expression(body, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Suite_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* body; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Suite field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Suite"); + return 1; } - if (isinstance) { - asdl_seq* body; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Interactive field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive"); - return 1; - } - *out = Interactive(body, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Expression_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty body; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &body, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression"); - return 1; - } - *out = Expression(body, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Suite_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - asdl_seq* body; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Suite field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Suite"); - return 1; - } - *out = Suite(body, arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of mod, but got %R", obj); - failed: - Py_XDECREF(tmp); - return 1; + *out = Suite(body, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of mod, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - int lineno; - int col_offset; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + int lineno; + int col_offset; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + if (_PyObject_HasAttrId(obj, &PyId_lineno)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_lineno); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &lineno, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &col_offset, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt"); + return 1; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)FunctionDef_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier name; + arguments_ty args; + asdl_seq* body; + asdl_seq* decorator_list; + expr_ty returns; + + if (_PyObject_HasAttrId(obj, &PyId_name)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_name); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &name, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_lineno)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_lineno); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &lineno, arena); + if (_PyObject_HasAttrId(obj, &PyId_args)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_args); + if (tmp == NULL) goto failed; + res = obj2ast_arguments(tmp, &args, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "FunctionDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &col_offset, arena); + if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "FunctionDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + decorator_list = asdl_seq_new(len, arena); + if (decorator_list == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(decorator_list, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)FunctionDef_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_returns)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_returns); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &returns, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + returns = NULL; } - if (isinstance) { - identifier name; - arguments_ty args; - asdl_seq* body; - asdl_seq* decorator_list; - expr_ty returns; - - if (_PyObject_HasAttrId(obj, &PyId_name)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_name); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &name, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_args)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_args); - if (tmp == NULL) goto failed; - res = obj2ast_arguments(tmp, &args, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "FunctionDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "FunctionDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - decorator_list = asdl_seq_new(len, arena); - if (decorator_list == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(decorator_list, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_returns)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_returns); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &returns, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - returns = NULL; - } - *out = FunctionDef(name, args, body, decorator_list, returns, - lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = FunctionDef(name, args, body, decorator_list, returns, lineno, + col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ClassDef_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier name; + asdl_seq* bases; + asdl_seq* keywords; + expr_ty starargs; + expr_ty kwargs; + asdl_seq* body; + asdl_seq* decorator_list; + + if (_PyObject_HasAttrId(obj, &PyId_name)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_name); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &name, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)ClassDef_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_bases)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_bases); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"bases\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + bases = asdl_seq_new(len, arena); + if (bases == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(bases, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef"); + return 1; } - if (isinstance) { - identifier name; - asdl_seq* bases; - asdl_seq* keywords; - expr_ty starargs; - expr_ty kwargs; - asdl_seq* body; - asdl_seq* decorator_list; - - if (_PyObject_HasAttrId(obj, &PyId_name)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_name); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &name, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_bases)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_bases); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"bases\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - bases = asdl_seq_new(len, arena); - if (bases == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(bases, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_keywords)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_keywords); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - keywords = asdl_seq_new(len, arena); - if (keywords == NULL) goto failed; - for (i = 0; i < len; i++) { - keyword_ty value; - res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(keywords, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_starargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_starargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &starargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - starargs = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_kwargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &kwargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - kwargs = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - decorator_list = asdl_seq_new(len, arena); - if (decorator_list == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(decorator_list, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef"); - return 1; - } - *out = ClassDef(name, bases, keywords, starargs, kwargs, body, - decorator_list, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_keywords)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_keywords); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + keywords = asdl_seq_new(len, arena); + if (keywords == NULL) goto failed; + for (i = 0; i < len; i++) { + keyword_ty value; + res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(keywords, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Return_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_starargs)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_starargs); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &starargs, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + starargs = NULL; } - if (isinstance) { + if (_PyObject_HasAttrId(obj, &PyId_kwargs)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &kwargs, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + kwargs = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + decorator_list = asdl_seq_new(len, arena); + if (decorator_list == NULL) goto failed; + for (i = 0; i < len; i++) { expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - value = NULL; - } - *out = Return(value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(decorator_list, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Delete_type); - if (isinstance == -1) { - return 1; + *out = ClassDef(name, bases, keywords, starargs, kwargs, body, + decorator_list, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Return_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + value = NULL; } - if (isinstance) { - asdl_seq* targets; - - if (_PyObject_HasAttrId(obj, &PyId_targets)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_targets); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Delete field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - targets = asdl_seq_new(len, arena); - if (targets == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(targets, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete"); - return 1; - } - *out = Delete(targets, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Return(value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Delete_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* targets; + + if (_PyObject_HasAttrId(obj, &PyId_targets)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_targets); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Delete field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + targets = asdl_seq_new(len, arena); + if (targets == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(targets, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Assign_type); - if (isinstance == -1) { - return 1; + *out = Delete(targets, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Assign_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* targets; + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_targets)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_targets); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Assign field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + targets = asdl_seq_new(len, arena); + if (targets == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(targets, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign"); + return 1; } - if (isinstance) { - asdl_seq* targets; - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_targets)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_targets); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Assign field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - targets = asdl_seq_new(len, arena); - if (targets == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(targets, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign"); - return 1; - } - *out = Assign(targets, value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)AugAssign_type); - if (isinstance == -1) { - return 1; + *out = Assign(targets, value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)AugAssign_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty target; + operator_ty op; + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_target)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_target); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &target, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign"); + return 1; } - if (isinstance) { - expr_ty target; - operator_ty op; - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_target)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_target); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &target, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_op)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_op); - if (tmp == NULL) goto failed; - res = obj2ast_operator(tmp, &op, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign"); - return 1; - } - *out = AugAssign(target, op, value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_op)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_op); + if (tmp == NULL) goto failed; + res = obj2ast_operator(tmp, &op, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)For_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign"); + return 1; } - if (isinstance) { - expr_ty target; - expr_ty iter; - asdl_seq* body; - asdl_seq* orelse; - - if (_PyObject_HasAttrId(obj, &PyId_target)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_target); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &target, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_iter)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_iter); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &iter, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "For field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "For field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - orelse = asdl_seq_new(len, arena); - if (orelse == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(orelse, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For"); - return 1; - } - *out = For(target, iter, body, orelse, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; + *out = AugAssign(target, op, value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)For_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty target; + expr_ty iter; + asdl_seq* body; + asdl_seq* orelse; + + if (_PyObject_HasAttrId(obj, &PyId_target)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_target); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &target, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)While_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_iter)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_iter); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &iter, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For"); + return 1; } - if (isinstance) { - expr_ty test; - asdl_seq* body; - asdl_seq* orelse; - - if (_PyObject_HasAttrId(obj, &PyId_test)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_test); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &test, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "While field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "While field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - orelse = asdl_seq_new(len, arena); - if (orelse == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(orelse, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While"); - return 1; - } - *out = While(test, body, orelse, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "For field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)If_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "For field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + orelse = asdl_seq_new(len, arena); + if (orelse == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(orelse, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For"); + return 1; } - if (isinstance) { - expr_ty test; - asdl_seq* body; - asdl_seq* orelse; - - if (_PyObject_HasAttrId(obj, &PyId_test)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_test); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &test, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "If field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "If field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - orelse = asdl_seq_new(len, arena); - if (orelse == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(orelse, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If"); - return 1; - } - *out = If(test, body, orelse, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = For(target, iter, body, orelse, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)While_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty test; + asdl_seq* body; + asdl_seq* orelse; + + if (_PyObject_HasAttrId(obj, &PyId_test)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_test); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &test, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)With_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "While field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While"); + return 1; } - if (isinstance) { - asdl_seq* items; - asdl_seq* body; - - if (_PyObject_HasAttrId(obj, &PyId_items)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_items); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "With field \"items\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - items = asdl_seq_new(len, arena); - if (items == NULL) goto failed; - for (i = 0; i < len; i++) { - withitem_ty value; - res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(items, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "With field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With"); - return 1; - } - *out = With(items, body, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "While field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + orelse = asdl_seq_new(len, arena); + if (orelse == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(orelse, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Raise_type); - if (isinstance == -1) { - return 1; + *out = While(test, body, orelse, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)If_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty test; + asdl_seq* body; + asdl_seq* orelse; + + if (_PyObject_HasAttrId(obj, &PyId_test)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_test); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &test, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If"); + return 1; } - if (isinstance) { - expr_ty exc; - expr_ty cause; - - if (_PyObject_HasAttrId(obj, &PyId_exc)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_exc); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &exc, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - exc = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_cause)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_cause); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &cause, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - cause = NULL; - } - *out = Raise(exc, cause, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "If field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Try_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "If field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + orelse = asdl_seq_new(len, arena); + if (orelse == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(orelse, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If"); + return 1; } - if (isinstance) { - asdl_seq* body; - asdl_seq* handlers; - asdl_seq* orelse; - asdl_seq* finalbody; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Try field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_handlers)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_handlers); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Try field \"handlers\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - handlers = asdl_seq_new(len, arena); - if (handlers == NULL) goto failed; - for (i = 0; i < len; i++) { - excepthandler_ty value; - res = obj2ast_excepthandler(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(handlers, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Try field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - orelse = asdl_seq_new(len, arena); - if (orelse == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(orelse, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_finalbody)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_finalbody); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Try field \"finalbody\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - finalbody = asdl_seq_new(len, arena); - if (finalbody == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(finalbody, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try"); - return 1; - } - *out = Try(body, handlers, orelse, finalbody, lineno, - col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = If(test, body, orelse, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)With_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* items; + asdl_seq* body; + + if (_PyObject_HasAttrId(obj, &PyId_items)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_items); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "With field \"items\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + items = asdl_seq_new(len, arena); + if (items == NULL) goto failed; + for (i = 0; i < len; i++) { + withitem_ty value; + res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(items, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Assert_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "With field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With"); + return 1; } - if (isinstance) { - expr_ty test; - expr_ty msg; - - if (_PyObject_HasAttrId(obj, &PyId_test)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_test); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &test, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_msg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_msg); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &msg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - msg = NULL; - } - *out = Assert(test, msg, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = With(items, body, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Raise_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty exc; + expr_ty cause; + + if (_PyObject_HasAttrId(obj, &PyId_exc)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_exc); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &exc, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + exc = NULL; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Import_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_cause)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_cause); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &cause, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + cause = NULL; } - if (isinstance) { - asdl_seq* names; - - if (_PyObject_HasAttrId(obj, &PyId_names)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_names); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Import field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - names = asdl_seq_new(len, arena); - if (names == NULL) goto failed; - for (i = 0; i < len; i++) { - alias_ty value; - res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(names, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import"); - return 1; - } - *out = Import(names, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Raise(exc, cause, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Try_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* body; + asdl_seq* handlers; + asdl_seq* orelse; + asdl_seq* finalbody; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Try field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)ImportFrom_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_handlers)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_handlers); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Try field \"handlers\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + handlers = asdl_seq_new(len, arena); + if (handlers == NULL) goto failed; + for (i = 0; i < len; i++) { + excepthandler_ty value; + res = obj2ast_excepthandler(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(handlers, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try"); + return 1; } - if (isinstance) { - identifier module; - asdl_seq* names; - int level; - - if (_PyObject_HasAttrId(obj, &PyId_module)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_module); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &module, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - module = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_names)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_names); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ImportFrom field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - names = asdl_seq_new(len, arena); - if (names == NULL) goto failed; - for (i = 0; i < len; i++) { - alias_ty value; - res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(names, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_level)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_level); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &level, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - level = 0; - } - *out = ImportFrom(module, names, level, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Try field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + orelse = asdl_seq_new(len, arena); + if (orelse == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(orelse, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Global_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_finalbody)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_finalbody); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Try field \"finalbody\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + finalbody = asdl_seq_new(len, arena); + if (finalbody == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(finalbody, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try"); + return 1; } - if (isinstance) { - asdl_seq* names; - - if (_PyObject_HasAttrId(obj, &PyId_names)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_names); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Global field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - names = asdl_seq_new(len, arena); - if (names == NULL) goto failed; - for (i = 0; i < len; i++) { - identifier value; - res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(names, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global"); - return 1; - } - *out = Global(names, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Try(body, handlers, orelse, finalbody, lineno, col_offset, + arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Assert_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty test; + expr_ty msg; + + if (_PyObject_HasAttrId(obj, &PyId_test)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_test); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &test, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Nonlocal_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_msg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_msg); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &msg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + msg = NULL; } - if (isinstance) { - asdl_seq* names; - - if (_PyObject_HasAttrId(obj, &PyId_names)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_names); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Nonlocal field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - names = asdl_seq_new(len, arena); - if (names == NULL) goto failed; - for (i = 0; i < len; i++) { - identifier value; - res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(names, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal"); - return 1; - } - *out = Nonlocal(names, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Assert(test, msg, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Import_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* names; + + if (_PyObject_HasAttrId(obj, &PyId_names)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_names); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Import field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + names = asdl_seq_new(len, arena); + if (names == NULL) goto failed; + for (i = 0; i < len; i++) { + alias_ty value; + res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(names, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Expr_type); - if (isinstance == -1) { - return 1; + *out = Import(names, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ImportFrom_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier module; + asdl_seq* names; + int level; + + if (_PyObject_HasAttrId(obj, &PyId_module)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_module); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &module, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + module = NULL; } - if (isinstance) { - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr"); - return 1; - } - *out = Expr(value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_names)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_names); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ImportFrom field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + names = asdl_seq_new(len, arena); + if (names == NULL) goto failed; + for (i = 0; i < len; i++) { + alias_ty value; + res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(names, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Pass_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_level)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_level); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &level, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + level = 0; } - if (isinstance) { - - *out = Pass(lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = ImportFrom(module, names, level, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Global_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* names; + + if (_PyObject_HasAttrId(obj, &PyId_names)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_names); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Global field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + names = asdl_seq_new(len, arena); + if (names == NULL) goto failed; + for (i = 0; i < len; i++) { + identifier value; + res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(names, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Break_type); - if (isinstance == -1) { - return 1; + *out = Global(names, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Nonlocal_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* names; + + if (_PyObject_HasAttrId(obj, &PyId_names)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_names); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Nonlocal field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + names = asdl_seq_new(len, arena); + if (names == NULL) goto failed; + for (i = 0; i < len; i++) { + identifier value; + res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(names, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal"); + return 1; } - if (isinstance) { - - *out = Break(lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Nonlocal(names, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Expr_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Continue_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - - *out = Continue(lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of stmt, but got %R", obj); - failed: - Py_XDECREF(tmp); + *out = Expr(value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Pass_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + + *out = Pass(lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Break_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + + *out = Break(lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Continue_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + + *out = Continue(lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of stmt, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - int lineno; - int col_offset; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + int lineno; + int col_offset; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + if (_PyObject_HasAttrId(obj, &PyId_lineno)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_lineno); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &lineno, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &col_offset, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr"); + return 1; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)BoolOp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + boolop_ty op; + asdl_seq* values; + + if (_PyObject_HasAttrId(obj, &PyId_op)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_op); + if (tmp == NULL) goto failed; + res = obj2ast_boolop(tmp, &op, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_lineno)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_lineno); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &lineno, arena); + if (_PyObject_HasAttrId(obj, &PyId_values)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_values); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "BoolOp field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + values = asdl_seq_new(len, arena); + if (values == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(values, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &col_offset, arena); + *out = BoolOp(op, values, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)BinOp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty left; + operator_ty op; + expr_ty right; + + if (_PyObject_HasAttrId(obj, &PyId_left)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_left); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &left, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_op)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_op); + if (tmp == NULL) goto failed; + res = obj2ast_operator(tmp, &op, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_right)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_right); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &right, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp"); + return 1; + } + *out = BinOp(left, op, right, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)UnaryOp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + unaryop_ty op; + expr_ty operand; + + if (_PyObject_HasAttrId(obj, &PyId_op)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_op); + if (tmp == NULL) goto failed; + res = obj2ast_unaryop(tmp, &op, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_operand)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_operand); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &operand, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp"); + return 1; + } + *out = UnaryOp(op, operand, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Lambda_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + arguments_ty args; + expr_ty body; + + if (_PyObject_HasAttrId(obj, &PyId_args)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_args); + if (tmp == NULL) goto failed; + res = obj2ast_arguments(tmp, &args, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &body, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda"); + return 1; + } + *out = Lambda(args, body, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)IfExp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty test; + expr_ty body; + expr_ty orelse; + + if (_PyObject_HasAttrId(obj, &PyId_test)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_test); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &test, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &body, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &orelse, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp"); + return 1; + } + *out = IfExp(test, body, orelse, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Dict_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* keys; + asdl_seq* values; + + if (_PyObject_HasAttrId(obj, &PyId_keys)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_keys); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Dict field \"keys\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + keys = asdl_seq_new(len, arena); + if (keys == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(keys, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)BoolOp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_values)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_values); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Dict field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + values = asdl_seq_new(len, arena); + if (values == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(values, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict"); + return 1; } - if (isinstance) { - boolop_ty op; - asdl_seq* values; - - if (_PyObject_HasAttrId(obj, &PyId_op)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_op); - if (tmp == NULL) goto failed; - res = obj2ast_boolop(tmp, &op, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_values)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_values); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "BoolOp field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - values = asdl_seq_new(len, arena); - if (values == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(values, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp"); - return 1; - } - *out = BoolOp(op, values, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Dict(keys, values, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Set_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* elts; + + if (_PyObject_HasAttrId(obj, &PyId_elts)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_elts); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Set field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + elts = asdl_seq_new(len, arena); + if (elts == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(elts, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)BinOp_type); - if (isinstance == -1) { - return 1; + *out = Set(elts, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ListComp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty elt; + asdl_seq* generators; + + if (_PyObject_HasAttrId(obj, &PyId_elt)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_elt); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &elt, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp"); + return 1; } - if (isinstance) { - expr_ty left; - operator_ty op; - expr_ty right; - - if (_PyObject_HasAttrId(obj, &PyId_left)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_left); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &left, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_op)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_op); - if (tmp == NULL) goto failed; - res = obj2ast_operator(tmp, &op, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_right)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_right); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &right, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp"); - return 1; - } - *out = BinOp(left, op, right, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_generators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_generators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ListComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + generators = asdl_seq_new(len, arena); + if (generators == NULL) goto failed; + for (i = 0; i < len; i++) { + comprehension_ty value; + res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(generators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)UnaryOp_type); - if (isinstance == -1) { - return 1; + *out = ListComp(elt, generators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)SetComp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty elt; + asdl_seq* generators; + + if (_PyObject_HasAttrId(obj, &PyId_elt)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_elt); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &elt, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp"); + return 1; } - if (isinstance) { - unaryop_ty op; - expr_ty operand; - - if (_PyObject_HasAttrId(obj, &PyId_op)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_op); - if (tmp == NULL) goto failed; - res = obj2ast_unaryop(tmp, &op, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_operand)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_operand); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &operand, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp"); - return 1; - } - *out = UnaryOp(op, operand, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_generators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_generators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "SetComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + generators = asdl_seq_new(len, arena); + if (generators == NULL) goto failed; + for (i = 0; i < len; i++) { + comprehension_ty value; + res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(generators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Lambda_type); - if (isinstance == -1) { - return 1; + *out = SetComp(elt, generators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)DictComp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty key; + expr_ty value; + asdl_seq* generators; + + if (_PyObject_HasAttrId(obj, &PyId_key)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_key); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &key, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp"); + return 1; } - if (isinstance) { - arguments_ty args; - expr_ty body; - - if (_PyObject_HasAttrId(obj, &PyId_args)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_args); - if (tmp == NULL) goto failed; - res = obj2ast_arguments(tmp, &args, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &body, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda"); - return 1; - } - *out = Lambda(args, body, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)IfExp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_generators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_generators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "DictComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + generators = asdl_seq_new(len, arena); + if (generators == NULL) goto failed; + for (i = 0; i < len; i++) { + comprehension_ty value; + res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(generators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp"); + return 1; } - if (isinstance) { - expr_ty test; - expr_ty body; - expr_ty orelse; - - if (_PyObject_HasAttrId(obj, &PyId_test)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_test); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &test, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &body, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &orelse, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp"); - return 1; - } - *out = IfExp(test, body, orelse, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = DictComp(key, value, generators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)GeneratorExp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty elt; + asdl_seq* generators; + + if (_PyObject_HasAttrId(obj, &PyId_elt)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_elt); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &elt, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Dict_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_generators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_generators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "GeneratorExp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + generators = asdl_seq_new(len, arena); + if (generators == NULL) goto failed; + for (i = 0; i < len; i++) { + comprehension_ty value; + res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(generators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp"); + return 1; } - if (isinstance) { - asdl_seq* keys; - asdl_seq* values; - - if (_PyObject_HasAttrId(obj, &PyId_keys)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_keys); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Dict field \"keys\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - keys = asdl_seq_new(len, arena); - if (keys == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(keys, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_values)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_values); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Dict field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - values = asdl_seq_new(len, arena); - if (values == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(values, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict"); - return 1; - } - *out = Dict(keys, values, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = GeneratorExp(elt, generators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Yield_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + value = NULL; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Set_type); - if (isinstance == -1) { - return 1; + *out = Yield(value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)YieldFrom_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom"); + return 1; } - if (isinstance) { - asdl_seq* elts; - - if (_PyObject_HasAttrId(obj, &PyId_elts)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_elts); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Set field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - elts = asdl_seq_new(len, arena); - if (elts == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(elts, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set"); - return 1; - } - *out = Set(elts, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = YieldFrom(value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Compare_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty left; + asdl_int_seq* ops; + asdl_seq* comparators; + + if (_PyObject_HasAttrId(obj, &PyId_left)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_left); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &left, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)ListComp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_ops)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_ops); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Compare field \"ops\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + ops = asdl_int_seq_new(len, arena); + if (ops == NULL) goto failed; + for (i = 0; i < len; i++) { + cmpop_ty value; + res = obj2ast_cmpop(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(ops, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare"); + return 1; } - if (isinstance) { - expr_ty elt; - asdl_seq* generators; - - if (_PyObject_HasAttrId(obj, &PyId_elt)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_elt); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &elt, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_generators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_generators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ListComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - generators = asdl_seq_new(len, arena); - if (generators == NULL) goto failed; - for (i = 0; i < len; i++) { - comprehension_ty value; - res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(generators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp"); - return 1; - } - *out = ListComp(elt, generators, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_comparators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_comparators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Compare field \"comparators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + comparators = asdl_seq_new(len, arena); + if (comparators == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(comparators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)SetComp_type); - if (isinstance == -1) { - return 1; + *out = Compare(left, ops, comparators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Call_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty func; + asdl_seq* args; + asdl_seq* keywords; + expr_ty starargs; + expr_ty kwargs; + + if (_PyObject_HasAttrId(obj, &PyId_func)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_func); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &func, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call"); + return 1; } - if (isinstance) { - expr_ty elt; - asdl_seq* generators; - - if (_PyObject_HasAttrId(obj, &PyId_elt)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_elt); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &elt, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_generators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_generators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "SetComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - generators = asdl_seq_new(len, arena); - if (generators == NULL) goto failed; - for (i = 0; i < len; i++) { - comprehension_ty value; - res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(generators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp"); - return 1; - } - *out = SetComp(elt, generators, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_args)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_args); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Call field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + args = asdl_seq_new(len, arena); + if (args == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(args, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)DictComp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_keywords)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_keywords); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Call field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + keywords = asdl_seq_new(len, arena); + if (keywords == NULL) goto failed; + for (i = 0; i < len; i++) { + keyword_ty value; + res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(keywords, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); + return 1; } - if (isinstance) { - expr_ty key; + if (_PyObject_HasAttrId(obj, &PyId_starargs)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_starargs); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &starargs, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + starargs = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_kwargs)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &kwargs, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + kwargs = NULL; + } + *out = Call(func, args, keywords, starargs, kwargs, lineno, col_offset, + arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Num_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + object n; + + if (_PyObject_HasAttrId(obj, &PyId_n)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_n); + if (tmp == NULL) goto failed; + res = obj2ast_object(tmp, &n, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"n\" missing from Num"); + return 1; + } + *out = Num(n, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Str_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + string s; + + if (_PyObject_HasAttrId(obj, &PyId_s)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_s); + if (tmp == NULL) goto failed; + res = obj2ast_string(tmp, &s, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Str"); + return 1; + } + *out = Str(s, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Bytes_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + bytes s; + + if (_PyObject_HasAttrId(obj, &PyId_s)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_s); + if (tmp == NULL) goto failed; + res = obj2ast_bytes(tmp, &s, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Bytes"); + return 1; + } + *out = Bytes(s, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Ellipsis_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + + *out = Ellipsis(lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Attribute_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + identifier attr; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_attr)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_attr); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &attr, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute"); + return 1; + } + *out = Attribute(value, attr, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Subscript_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + slice_ty slice; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_slice)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_slice); + if (tmp == NULL) goto failed; + res = obj2ast_slice(tmp, &slice, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript"); + return 1; + } + *out = Subscript(value, slice, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Starred_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred"); + return 1; + } + *out = Starred(value, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Name_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier id; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_id)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_id); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &id, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name"); + return 1; + } + *out = Name(id, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)List_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* elts; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_elts)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_elts); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "List field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + elts = asdl_seq_new(len, arena); + if (elts == NULL) goto failed; + for (i = 0; i < len; i++) { expr_ty value; - asdl_seq* generators; - - if (_PyObject_HasAttrId(obj, &PyId_key)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_key); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &key, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_generators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_generators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "DictComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - generators = asdl_seq_new(len, arena); - if (generators == NULL) goto failed; - for (i = 0; i < len; i++) { - comprehension_ty value; - res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(generators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp"); - return 1; - } - *out = DictComp(key, value, generators, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(elts, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)GeneratorExp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List"); + return 1; } - if (isinstance) { - expr_ty elt; - asdl_seq* generators; - - if (_PyObject_HasAttrId(obj, &PyId_elt)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_elt); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &elt, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_generators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_generators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "GeneratorExp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - generators = asdl_seq_new(len, arena); - if (generators == NULL) goto failed; - for (i = 0; i < len; i++) { - comprehension_ty value; - res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(generators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp"); - return 1; - } - *out = GeneratorExp(elt, generators, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = List(elts, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Tuple_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* elts; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_elts)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_elts); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Tuple field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + elts = asdl_seq_new(len, arena); + if (elts == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(elts, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Yield_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple"); + return 1; } - if (isinstance) { - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - value = NULL; - } - *out = Yield(value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)YieldFrom_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom"); - return 1; - } - *out = YieldFrom(value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Compare_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty left; - asdl_int_seq* ops; - asdl_seq* comparators; - - if (_PyObject_HasAttrId(obj, &PyId_left)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_left); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &left, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ops)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_ops); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Compare field \"ops\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - ops = asdl_int_seq_new(len, arena); - if (ops == NULL) goto failed; - for (i = 0; i < len; i++) { - cmpop_ty value; - res = obj2ast_cmpop(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(ops, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_comparators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_comparators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Compare field \"comparators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - comparators = asdl_seq_new(len, arena); - if (comparators == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(comparators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare"); - return 1; - } - *out = Compare(left, ops, comparators, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Call_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty func; - asdl_seq* args; - asdl_seq* keywords; - expr_ty starargs; - expr_ty kwargs; - - if (_PyObject_HasAttrId(obj, &PyId_func)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_func); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &func, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_args)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_args); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Call field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - args = asdl_seq_new(len, arena); - if (args == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(args, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_keywords)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_keywords); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Call field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - keywords = asdl_seq_new(len, arena); - if (keywords == NULL) goto failed; - for (i = 0; i < len; i++) { - keyword_ty value; - res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(keywords, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_starargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_starargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &starargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - starargs = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_kwargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &kwargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - kwargs = NULL; - } - *out = Call(func, args, keywords, starargs, kwargs, lineno, - col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Num_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - object n; - - if (_PyObject_HasAttrId(obj, &PyId_n)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_n); - if (tmp == NULL) goto failed; - res = obj2ast_object(tmp, &n, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"n\" missing from Num"); - return 1; - } - *out = Num(n, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Str_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - string s; - - if (_PyObject_HasAttrId(obj, &PyId_s)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_s); - if (tmp == NULL) goto failed; - res = obj2ast_string(tmp, &s, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Str"); - return 1; - } - *out = Str(s, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Bytes_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - bytes s; - - if (_PyObject_HasAttrId(obj, &PyId_s)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_s); - if (tmp == NULL) goto failed; - res = obj2ast_bytes(tmp, &s, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Bytes"); - return 1; - } - *out = Bytes(s, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Ellipsis_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - - *out = Ellipsis(lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Attribute_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - identifier attr; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_attr)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_attr); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &attr, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute"); - return 1; - } - *out = Attribute(value, attr, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Subscript_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - slice_ty slice; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_slice)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_slice); - if (tmp == NULL) goto failed; - res = obj2ast_slice(tmp, &slice, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript"); - return 1; - } - *out = Subscript(value, slice, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Starred_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred"); - return 1; - } - *out = Starred(value, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Name_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - identifier id; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_id)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_id); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &id, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name"); - return 1; - } - *out = Name(id, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)List_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - asdl_seq* elts; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_elts)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_elts); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "List field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - elts = asdl_seq_new(len, arena); - if (elts == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(elts, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List"); - return 1; - } - *out = List(elts, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Tuple_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - asdl_seq* elts; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_elts)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_elts); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Tuple field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - elts = asdl_seq_new(len, arena); - if (elts == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(elts, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple"); - return 1; - } - *out = Tuple(elts, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of expr, but got %R", obj); - failed: - Py_XDECREF(tmp); - return 1; + *out = Tuple(elts, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of expr, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_expr_context(PyObject* obj, expr_context_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)Load_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Load; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Store_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Store; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Del_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Del; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)AugLoad_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = AugLoad; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)AugStore_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = AugStore; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Param_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Param; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of expr_context, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)Load_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = Load; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Store_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Store; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Del_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Del; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)AugLoad_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = AugLoad; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)AugStore_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = AugStore; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Param_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Param; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of expr_context, but got %R", obj); + return 1; } int obj2ast_slice(PyObject* obj, slice_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Slice_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty lower; + expr_ty upper; + expr_ty step; + + if (_PyObject_HasAttrId(obj, &PyId_lower)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_lower); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &lower, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + lower = NULL; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Slice_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_upper)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_upper); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &upper, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + upper = NULL; } - if (isinstance) { - expr_ty lower; - expr_ty upper; - expr_ty step; - - if (_PyObject_HasAttrId(obj, &PyId_lower)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_lower); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &lower, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - lower = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_upper)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_upper); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &upper, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - upper = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_step)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_step); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &step, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - step = NULL; - } - *out = Slice(lower, upper, step, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_step)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_step); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &step, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + step = NULL; } - isinstance = PyObject_IsInstance(obj, (PyObject*)ExtSlice_type); - if (isinstance == -1) { - return 1; + *out = Slice(lower, upper, step, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ExtSlice_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* dims; + + if (_PyObject_HasAttrId(obj, &PyId_dims)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_dims); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ExtSlice field \"dims\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + dims = asdl_seq_new(len, arena); + if (dims == NULL) goto failed; + for (i = 0; i < len; i++) { + slice_ty value; + res = obj2ast_slice(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(dims, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"dims\" missing from ExtSlice"); + return 1; } - if (isinstance) { - asdl_seq* dims; - - if (_PyObject_HasAttrId(obj, &PyId_dims)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_dims); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ExtSlice field \"dims\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - dims = asdl_seq_new(len, arena); - if (dims == NULL) goto failed; - for (i = 0; i < len; i++) { - slice_ty value; - res = obj2ast_slice(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(dims, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"dims\" missing from ExtSlice"); - return 1; - } - *out = ExtSlice(dims, arena); - if (*out == NULL) goto failed; - return 0; + *out = ExtSlice(dims, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Index_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Index"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Index_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Index"); - return 1; - } - *out = Index(value, arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of slice, but got %R", obj); - failed: - Py_XDECREF(tmp); - return 1; + *out = Index(value, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of slice, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_boolop(PyObject* obj, boolop_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)And_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = And; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Or_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Or; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of boolop, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)And_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = And; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Or_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Or; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of boolop, but got %R", obj); + return 1; } int obj2ast_operator(PyObject* obj, operator_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)Add_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Add; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Sub_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Sub; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Mult_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Mult; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Div_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Div; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Mod_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Mod; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Pow_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Pow; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)LShift_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = LShift; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)RShift_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = RShift; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)BitOr_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = BitOr; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)BitXor_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = BitXor; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)BitAnd_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = BitAnd; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)FloorDiv_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = FloorDiv; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of operator, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)Add_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = Add; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Sub_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Sub; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Mult_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Mult; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Div_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Div; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Mod_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Mod; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Pow_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Pow; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)LShift_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = LShift; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)RShift_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = RShift; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)BitOr_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = BitOr; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)BitXor_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = BitXor; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)BitAnd_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = BitAnd; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)FloorDiv_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = FloorDiv; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of operator, but got %R", obj); + return 1; } int obj2ast_unaryop(PyObject* obj, unaryop_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)Invert_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Invert; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Not_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Not; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)UAdd_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = UAdd; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)USub_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = USub; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of unaryop, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)Invert_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = Invert; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Not_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Not; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)UAdd_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = UAdd; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)USub_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = USub; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of unaryop, but got %R", obj); + return 1; } int obj2ast_cmpop(PyObject* obj, cmpop_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)Eq_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Eq; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)NotEq_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = NotEq; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Lt_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Lt; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)LtE_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = LtE; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Gt_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Gt; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)GtE_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = GtE; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Is_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Is; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)IsNot_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = IsNot; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)In_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = In; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)NotIn_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = NotIn; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of cmpop, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)Eq_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = Eq; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)NotEq_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = NotEq; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Lt_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Lt; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)LtE_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = LtE; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Gt_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Gt; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)GtE_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = GtE; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Is_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Is; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)IsNot_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = IsNot; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)In_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = In; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)NotIn_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = NotIn; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of cmpop, but got %R", obj); + return 1; } int obj2ast_comprehension(PyObject* obj, comprehension_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - expr_ty target; - expr_ty iter; - asdl_seq* ifs; - - if (_PyObject_HasAttrId(obj, &PyId_target)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_target); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &target, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension"); - return 1; + PyObject* tmp = NULL; + expr_ty target; + expr_ty iter; + asdl_seq* ifs; + + if (_PyObject_HasAttrId(obj, &PyId_target)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_target); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &target, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_iter)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_iter); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &iter, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ifs)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_ifs); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "comprehension field \"ifs\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; } - if (_PyObject_HasAttrId(obj, &PyId_iter)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_iter); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &iter, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension"); - return 1; + len = PyList_GET_SIZE(tmp); + ifs = asdl_seq_new(len, arena); + if (ifs == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(ifs, i, value); } - if (_PyObject_HasAttrId(obj, &PyId_ifs)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_ifs); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "comprehension field \"ifs\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - ifs = asdl_seq_new(len, arena); - if (ifs == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(ifs, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension"); - return 1; - } - *out = comprehension(target, iter, ifs, arena); - return 0; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension"); + return 1; + } + *out = comprehension(target, iter, ifs, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_excepthandler(PyObject* obj, excepthandler_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - int lineno; - int col_offset; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + int lineno; + int col_offset; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + if (_PyObject_HasAttrId(obj, &PyId_lineno)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_lineno); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &lineno, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &col_offset, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler"); + return 1; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ExceptHandler_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty type; + identifier name; + asdl_seq* body; + + if (_PyObject_HasAttrId(obj, &PyId_type)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_type); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &type, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + type = NULL; } - if (_PyObject_HasAttrId(obj, &PyId_lineno)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_lineno); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &lineno, arena); + if (_PyObject_HasAttrId(obj, &PyId_name)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_name); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &name, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + name = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ExceptHandler field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &col_offset, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler"); - return 1; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)ExceptHandler_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty type; - identifier name; - asdl_seq* body; - - if (_PyObject_HasAttrId(obj, &PyId_type)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_type); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &type, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - type = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_name)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_name); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &name, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - name = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ExceptHandler field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler"); - return 1; - } - *out = ExceptHandler(type, name, body, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of excepthandler, but got %R", obj); - failed: - Py_XDECREF(tmp); - return 1; + *out = ExceptHandler(type, name, body, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of excepthandler, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - asdl_seq* args; - identifier vararg; - expr_ty varargannotation; - asdl_seq* kwonlyargs; - identifier kwarg; - expr_ty kwargannotation; - asdl_seq* defaults; - asdl_seq* kw_defaults; - - if (_PyObject_HasAttrId(obj, &PyId_args)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_args); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "arguments field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - args = asdl_seq_new(len, arena); - if (args == NULL) goto failed; - for (i = 0; i < len; i++) { - arg_ty value; - res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(args, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments"); - return 1; + PyObject* tmp = NULL; + asdl_seq* args; + identifier vararg; + expr_ty varargannotation; + asdl_seq* kwonlyargs; + identifier kwarg; + expr_ty kwargannotation; + asdl_seq* defaults; + asdl_seq* kw_defaults; + + if (_PyObject_HasAttrId(obj, &PyId_args)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_args); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "arguments field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; } - if (_PyObject_HasAttrId(obj, &PyId_vararg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_vararg); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &vararg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - vararg = NULL; + len = PyList_GET_SIZE(tmp); + args = asdl_seq_new(len, arena); + if (args == NULL) goto failed; + for (i = 0; i < len; i++) { + arg_ty value; + res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(args, i, value); } - if (_PyObject_HasAttrId(obj, &PyId_varargannotation)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_varargannotation); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &varargannotation, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - varargannotation = NULL; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_vararg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_vararg); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &vararg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + vararg = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_varargannotation)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_varargannotation); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &varargannotation, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + varargannotation = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_kwonlyargs)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_kwonlyargs); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "arguments field \"kwonlyargs\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; } - if (_PyObject_HasAttrId(obj, &PyId_kwonlyargs)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_kwonlyargs); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "arguments field \"kwonlyargs\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - kwonlyargs = asdl_seq_new(len, arena); - if (kwonlyargs == NULL) goto failed; - for (i = 0; i < len; i++) { - arg_ty value; - res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(kwonlyargs, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments"); - return 1; + len = PyList_GET_SIZE(tmp); + kwonlyargs = asdl_seq_new(len, arena); + if (kwonlyargs == NULL) goto failed; + for (i = 0; i < len; i++) { + arg_ty value; + res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(kwonlyargs, i, value); } - if (_PyObject_HasAttrId(obj, &PyId_kwarg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_kwarg); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &kwarg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - kwarg = NULL; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_kwarg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_kwarg); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &kwarg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + kwarg = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_kwargannotation)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_kwargannotation); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &kwargannotation, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + kwargannotation = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_defaults)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_defaults); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "arguments field \"defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; } - if (_PyObject_HasAttrId(obj, &PyId_kwargannotation)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_kwargannotation); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &kwargannotation, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - kwargannotation = NULL; + len = PyList_GET_SIZE(tmp); + defaults = asdl_seq_new(len, arena); + if (defaults == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(defaults, i, value); } - if (_PyObject_HasAttrId(obj, &PyId_defaults)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_defaults); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "arguments field \"defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - defaults = asdl_seq_new(len, arena); - if (defaults == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(defaults, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments"); - return 1; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_kw_defaults)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_kw_defaults); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "arguments field \"kw_defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; } - if (_PyObject_HasAttrId(obj, &PyId_kw_defaults)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_kw_defaults); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "arguments field \"kw_defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - kw_defaults = asdl_seq_new(len, arena); - if (kw_defaults == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(kw_defaults, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments"); - return 1; + len = PyList_GET_SIZE(tmp); + kw_defaults = asdl_seq_new(len, arena); + if (kw_defaults == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(kw_defaults, i, value); } - *out = arguments(args, vararg, varargannotation, kwonlyargs, kwarg, - kwargannotation, defaults, kw_defaults, arena); - return 0; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments"); + return 1; + } + *out = arguments(args, vararg, varargannotation, kwonlyargs, kwarg, + kwargannotation, defaults, kw_defaults, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_arg(PyObject* obj, arg_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - identifier arg; - expr_ty annotation; - - if (_PyObject_HasAttrId(obj, &PyId_arg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_arg); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &arg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_annotation)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_annotation); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &annotation, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - annotation = NULL; - } - *out = arg(arg, annotation, arena); - return 0; + PyObject* tmp = NULL; + identifier arg; + expr_ty annotation; + + if (_PyObject_HasAttrId(obj, &PyId_arg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_arg); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &arg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_annotation)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_annotation); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &annotation, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + annotation = NULL; + } + *out = arg(arg, annotation, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_keyword(PyObject* obj, keyword_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - identifier arg; - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_arg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_arg); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &arg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from keyword"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword"); - return 1; - } - *out = keyword(arg, value, arena); - return 0; + PyObject* tmp = NULL; + identifier arg; + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_arg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_arg); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &arg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from keyword"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword"); + return 1; + } + *out = keyword(arg, value, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_alias(PyObject* obj, alias_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - identifier name; - identifier asname; - - if (_PyObject_HasAttrId(obj, &PyId_name)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_name); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &name, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_asname)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_asname); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &asname, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - asname = NULL; - } - *out = alias(name, asname, arena); - return 0; + PyObject* tmp = NULL; + identifier name; + identifier asname; + + if (_PyObject_HasAttrId(obj, &PyId_name)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_name); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &name, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_asname)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_asname); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &asname, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + asname = NULL; + } + *out = alias(name, asname, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_withitem(PyObject* obj, withitem_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - expr_ty context_expr; - expr_ty optional_vars; - - if (_PyObject_HasAttrId(obj, &PyId_context_expr)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_context_expr); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &context_expr, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_optional_vars)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_optional_vars); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &optional_vars, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - optional_vars = NULL; - } - *out = withitem(context_expr, optional_vars, arena); - return 0; + PyObject* tmp = NULL; + expr_ty context_expr; + expr_ty optional_vars; + + if (_PyObject_HasAttrId(obj, &PyId_context_expr)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_context_expr); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &context_expr, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_optional_vars)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_optional_vars); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &optional_vars, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + optional_vars = NULL; + } + *out = withitem(context_expr, optional_vars, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } @@ -6908,217 +6894,186 @@ PyMODINIT_FUNC PyInit__ast(void) { - PyObject *m, *d; - if (!init_types()) return NULL; - m = PyModule_Create(&_astmodule); - if (!m) return NULL; - 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) - return NULL; - if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Interactive", (PyObject*)Interactive_type) - < 0) return NULL; - if (PyDict_SetItemString(d, "Expression", (PyObject*)Expression_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Suite", (PyObject*)Suite_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "stmt", (PyObject*)stmt_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "FunctionDef", (PyObject*)FunctionDef_type) - < 0) return NULL; - if (PyDict_SetItemString(d, "ClassDef", (PyObject*)ClassDef_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Return", (PyObject*)Return_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Delete", (PyObject*)Delete_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Assign", (PyObject*)Assign_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "AugAssign", (PyObject*)AugAssign_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "For", (PyObject*)For_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "While", (PyObject*)While_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "If", (PyObject*)If_type) < 0) return NULL; - if (PyDict_SetItemString(d, "With", (PyObject*)With_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Raise", (PyObject*)Raise_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Try", (PyObject*)Try_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Assert", (PyObject*)Assert_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Import", (PyObject*)Import_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "ImportFrom", (PyObject*)ImportFrom_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Global", (PyObject*)Global_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Nonlocal", (PyObject*)Nonlocal_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Expr", (PyObject*)Expr_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Pass", (PyObject*)Pass_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Break", (PyObject*)Break_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Continue", (PyObject*)Continue_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "expr", (PyObject*)expr_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "BoolOp", (PyObject*)BoolOp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "BinOp", (PyObject*)BinOp_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "UnaryOp", (PyObject*)UnaryOp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Lambda", (PyObject*)Lambda_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "IfExp", (PyObject*)IfExp_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Dict", (PyObject*)Dict_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Set", (PyObject*)Set_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "ListComp", (PyObject*)ListComp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "SetComp", (PyObject*)SetComp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "DictComp", (PyObject*)DictComp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "GeneratorExp", - (PyObject*)GeneratorExp_type) < 0) return NULL; - if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "YieldFrom", (PyObject*)YieldFrom_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Compare", (PyObject*)Compare_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Call", (PyObject*)Call_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Num", (PyObject*)Num_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Str", (PyObject*)Str_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Bytes", (PyObject*)Bytes_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Subscript", (PyObject*)Subscript_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Starred", (PyObject*)Starred_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Name", (PyObject*)Name_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "List", (PyObject*)List_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Tuple", (PyObject*)Tuple_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "expr_context", - (PyObject*)expr_context_type) < 0) return NULL; - if (PyDict_SetItemString(d, "Load", (PyObject*)Load_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Store", (PyObject*)Store_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Del", (PyObject*)Del_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "AugLoad", (PyObject*)AugLoad_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "AugStore", (PyObject*)AugStore_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Param", (PyObject*)Param_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "slice", (PyObject*)slice_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Slice", (PyObject*)Slice_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "ExtSlice", (PyObject*)ExtSlice_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Index", (PyObject*)Index_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "boolop", (PyObject*)boolop_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "And", (PyObject*)And_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Or", (PyObject*)Or_type) < 0) return NULL; - if (PyDict_SetItemString(d, "operator", (PyObject*)operator_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Add", (PyObject*)Add_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Sub", (PyObject*)Sub_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Mult", (PyObject*)Mult_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Div", (PyObject*)Div_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Mod", (PyObject*)Mod_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Pow", (PyObject*)Pow_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "LShift", (PyObject*)LShift_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "RShift", (PyObject*)RShift_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "BitOr", (PyObject*)BitOr_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "BitXor", (PyObject*)BitXor_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "BitAnd", (PyObject*)BitAnd_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "FloorDiv", (PyObject*)FloorDiv_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "unaryop", (PyObject*)unaryop_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Invert", (PyObject*)Invert_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Not", (PyObject*)Not_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "UAdd", (PyObject*)UAdd_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "USub", (PyObject*)USub_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "cmpop", (PyObject*)cmpop_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Eq", (PyObject*)Eq_type) < 0) return NULL; - if (PyDict_SetItemString(d, "NotEq", (PyObject*)NotEq_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Lt", (PyObject*)Lt_type) < 0) return NULL; - if (PyDict_SetItemString(d, "LtE", (PyObject*)LtE_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Gt", (PyObject*)Gt_type) < 0) return NULL; - if (PyDict_SetItemString(d, "GtE", (PyObject*)GtE_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Is", (PyObject*)Is_type) < 0) return NULL; - if (PyDict_SetItemString(d, "IsNot", (PyObject*)IsNot_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "In", (PyObject*)In_type) < 0) return NULL; - if (PyDict_SetItemString(d, "NotIn", (PyObject*)NotIn_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "comprehension", - (PyObject*)comprehension_type) < 0) return NULL; - if (PyDict_SetItemString(d, "excepthandler", - (PyObject*)excepthandler_type) < 0) return NULL; - if (PyDict_SetItemString(d, "ExceptHandler", - (PyObject*)ExceptHandler_type) < 0) return NULL; - if (PyDict_SetItemString(d, "arguments", (PyObject*)arguments_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "arg", (PyObject*)arg_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "keyword", (PyObject*)keyword_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "alias", (PyObject*)alias_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "withitem", (PyObject*)withitem_type) < 0) - return NULL; - return m; + PyObject *m, *d; + if (!init_types()) return NULL; + m = PyModule_Create(&_astmodule); + if (!m) return NULL; + 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) + return NULL; + if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Interactive", (PyObject*)Interactive_type) < + 0) return NULL; + if (PyDict_SetItemString(d, "Expression", (PyObject*)Expression_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Suite", (PyObject*)Suite_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "stmt", (PyObject*)stmt_type) < 0) return NULL; + if (PyDict_SetItemString(d, "FunctionDef", (PyObject*)FunctionDef_type) < + 0) return NULL; + if (PyDict_SetItemString(d, "ClassDef", (PyObject*)ClassDef_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Return", (PyObject*)Return_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Delete", (PyObject*)Delete_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Assign", (PyObject*)Assign_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "AugAssign", (PyObject*)AugAssign_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "For", (PyObject*)For_type) < 0) return NULL; + if (PyDict_SetItemString(d, "While", (PyObject*)While_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "If", (PyObject*)If_type) < 0) return NULL; + if (PyDict_SetItemString(d, "With", (PyObject*)With_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Raise", (PyObject*)Raise_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Try", (PyObject*)Try_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Assert", (PyObject*)Assert_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Import", (PyObject*)Import_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "ImportFrom", (PyObject*)ImportFrom_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Global", (PyObject*)Global_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Nonlocal", (PyObject*)Nonlocal_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Expr", (PyObject*)Expr_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Pass", (PyObject*)Pass_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Break", (PyObject*)Break_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Continue", (PyObject*)Continue_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "expr", (PyObject*)expr_type) < 0) return NULL; + if (PyDict_SetItemString(d, "BoolOp", (PyObject*)BoolOp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "BinOp", (PyObject*)BinOp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "UnaryOp", (PyObject*)UnaryOp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Lambda", (PyObject*)Lambda_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "IfExp", (PyObject*)IfExp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Dict", (PyObject*)Dict_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Set", (PyObject*)Set_type) < 0) return NULL; + if (PyDict_SetItemString(d, "ListComp", (PyObject*)ListComp_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "SetComp", (PyObject*)SetComp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "DictComp", (PyObject*)DictComp_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "GeneratorExp", (PyObject*)GeneratorExp_type) < + 0) return NULL; + if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "YieldFrom", (PyObject*)YieldFrom_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Compare", (PyObject*)Compare_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Call", (PyObject*)Call_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Num", (PyObject*)Num_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Str", (PyObject*)Str_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Bytes", (PyObject*)Bytes_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Subscript", (PyObject*)Subscript_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Starred", (PyObject*)Starred_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Name", (PyObject*)Name_type) < 0) return NULL; + if (PyDict_SetItemString(d, "List", (PyObject*)List_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Tuple", (PyObject*)Tuple_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "expr_context", (PyObject*)expr_context_type) < + 0) return NULL; + if (PyDict_SetItemString(d, "Load", (PyObject*)Load_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Store", (PyObject*)Store_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Del", (PyObject*)Del_type) < 0) return NULL; + if (PyDict_SetItemString(d, "AugLoad", (PyObject*)AugLoad_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "AugStore", (PyObject*)AugStore_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Param", (PyObject*)Param_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "slice", (PyObject*)slice_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Slice", (PyObject*)Slice_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "ExtSlice", (PyObject*)ExtSlice_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Index", (PyObject*)Index_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "boolop", (PyObject*)boolop_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "And", (PyObject*)And_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Or", (PyObject*)Or_type) < 0) return NULL; + if (PyDict_SetItemString(d, "operator", (PyObject*)operator_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Add", (PyObject*)Add_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Sub", (PyObject*)Sub_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Mult", (PyObject*)Mult_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Div", (PyObject*)Div_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Mod", (PyObject*)Mod_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Pow", (PyObject*)Pow_type) < 0) return NULL; + if (PyDict_SetItemString(d, "LShift", (PyObject*)LShift_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "RShift", (PyObject*)RShift_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "BitOr", (PyObject*)BitOr_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "BitXor", (PyObject*)BitXor_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "BitAnd", (PyObject*)BitAnd_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "FloorDiv", (PyObject*)FloorDiv_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "unaryop", (PyObject*)unaryop_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Invert", (PyObject*)Invert_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Not", (PyObject*)Not_type) < 0) return NULL; + if (PyDict_SetItemString(d, "UAdd", (PyObject*)UAdd_type) < 0) return NULL; + if (PyDict_SetItemString(d, "USub", (PyObject*)USub_type) < 0) return NULL; + if (PyDict_SetItemString(d, "cmpop", (PyObject*)cmpop_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Eq", (PyObject*)Eq_type) < 0) return NULL; + if (PyDict_SetItemString(d, "NotEq", (PyObject*)NotEq_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Lt", (PyObject*)Lt_type) < 0) return NULL; + if (PyDict_SetItemString(d, "LtE", (PyObject*)LtE_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Gt", (PyObject*)Gt_type) < 0) return NULL; + if (PyDict_SetItemString(d, "GtE", (PyObject*)GtE_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Is", (PyObject*)Is_type) < 0) return NULL; + if (PyDict_SetItemString(d, "IsNot", (PyObject*)IsNot_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "In", (PyObject*)In_type) < 0) return NULL; + if (PyDict_SetItemString(d, "NotIn", (PyObject*)NotIn_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "comprehension", (PyObject*)comprehension_type) + < 0) return NULL; + if (PyDict_SetItemString(d, "excepthandler", (PyObject*)excepthandler_type) + < 0) return NULL; + if (PyDict_SetItemString(d, "ExceptHandler", (PyObject*)ExceptHandler_type) + < 0) return NULL; + if (PyDict_SetItemString(d, "arguments", (PyObject*)arguments_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "arg", (PyObject*)arg_type) < 0) return NULL; + if (PyDict_SetItemString(d, "keyword", (PyObject*)keyword_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "alias", (PyObject*)alias_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "withitem", (PyObject*)withitem_type) < 0) + return NULL; + return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 00:01:59 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 00:01:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_According_to_the_PEP_7=2C_C_code_must_?= =?utf-8?q?=22use_4-space_indents=22?= Message-ID: <3c245M3Fyqz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/1b464f8453a4 changeset: 84851:1b464f8453a4 parent: 84849:d543829eda7d parent: 84850:f2d557484906 user: Victor Stinner date: Sat Jul 27 00:01:35 2013 +0200 summary: (Merge 3.3) According to the PEP 7, C code must "use 4-space indents" Replace 8 spaces with 4. files: Include/Python-ast.h | 606 +- Parser/asdl_c.py | 2 +- Python/Python-ast.c | 11711 ++++++++++++++-------------- 3 files changed, 6137 insertions(+), 6182 deletions(-) diff --git a/Include/Python-ast.h b/Include/Python-ast.h --- a/Include/Python-ast.h +++ b/Include/Python-ast.h @@ -42,25 +42,25 @@ enum _mod_kind {Module_kind=1, Interactive_kind=2, Expression_kind=3, Suite_kind=4}; struct _mod { - enum _mod_kind kind; - union { - struct { - asdl_seq *body; - } Module; - - struct { - asdl_seq *body; - } Interactive; - - struct { - expr_ty body; - } Expression; - - struct { - asdl_seq *body; - } Suite; - - } v; + enum _mod_kind kind; + union { + struct { + asdl_seq *body; + } Module; + + struct { + asdl_seq *body; + } Interactive; + + struct { + expr_ty body; + } Expression; + + struct { + asdl_seq *body; + } Suite; + + } v; }; enum _stmt_kind {FunctionDef_kind=1, ClassDef_kind=2, Return_kind=3, @@ -70,111 +70,111 @@ ImportFrom_kind=15, Global_kind=16, Nonlocal_kind=17, Expr_kind=18, Pass_kind=19, Break_kind=20, Continue_kind=21}; struct _stmt { - enum _stmt_kind kind; - union { - struct { - identifier name; - arguments_ty args; - asdl_seq *body; - asdl_seq *decorator_list; - expr_ty returns; - } FunctionDef; - - struct { - identifier name; - asdl_seq *bases; - asdl_seq *keywords; - expr_ty starargs; - expr_ty kwargs; - asdl_seq *body; - asdl_seq *decorator_list; - } ClassDef; - - struct { - expr_ty value; - } Return; - - struct { - asdl_seq *targets; - } Delete; - - struct { - asdl_seq *targets; - expr_ty value; - } Assign; - - struct { - expr_ty target; - operator_ty op; - expr_ty value; - } AugAssign; - - struct { - expr_ty target; - expr_ty iter; - asdl_seq *body; - asdl_seq *orelse; - } For; - - struct { - expr_ty test; - asdl_seq *body; - asdl_seq *orelse; - } While; - - struct { - expr_ty test; - asdl_seq *body; - asdl_seq *orelse; - } If; - - struct { - asdl_seq *items; - asdl_seq *body; - } With; - - struct { - expr_ty exc; - expr_ty cause; - } Raise; - - struct { - asdl_seq *body; - asdl_seq *handlers; - asdl_seq *orelse; - asdl_seq *finalbody; - } Try; - - struct { - expr_ty test; - expr_ty msg; - } Assert; - - struct { - asdl_seq *names; - } Import; - - struct { - identifier module; - asdl_seq *names; - int level; - } ImportFrom; - - struct { - asdl_seq *names; - } Global; - - struct { - asdl_seq *names; - } Nonlocal; - - struct { - expr_ty value; - } Expr; - - } v; - int lineno; - int col_offset; + enum _stmt_kind kind; + union { + struct { + identifier name; + arguments_ty args; + asdl_seq *body; + asdl_seq *decorator_list; + expr_ty returns; + } FunctionDef; + + struct { + identifier name; + asdl_seq *bases; + asdl_seq *keywords; + expr_ty starargs; + expr_ty kwargs; + asdl_seq *body; + asdl_seq *decorator_list; + } ClassDef; + + struct { + expr_ty value; + } Return; + + struct { + asdl_seq *targets; + } Delete; + + struct { + asdl_seq *targets; + expr_ty value; + } Assign; + + struct { + expr_ty target; + operator_ty op; + expr_ty value; + } AugAssign; + + struct { + expr_ty target; + expr_ty iter; + asdl_seq *body; + asdl_seq *orelse; + } For; + + struct { + expr_ty test; + asdl_seq *body; + asdl_seq *orelse; + } While; + + struct { + expr_ty test; + asdl_seq *body; + asdl_seq *orelse; + } If; + + struct { + asdl_seq *items; + asdl_seq *body; + } With; + + struct { + expr_ty exc; + expr_ty cause; + } Raise; + + struct { + asdl_seq *body; + asdl_seq *handlers; + asdl_seq *orelse; + asdl_seq *finalbody; + } Try; + + struct { + expr_ty test; + expr_ty msg; + } Assert; + + struct { + asdl_seq *names; + } Import; + + struct { + identifier module; + asdl_seq *names; + int level; + } ImportFrom; + + struct { + asdl_seq *names; + } Global; + + struct { + asdl_seq *names; + } Nonlocal; + + struct { + expr_ty value; + } Expr; + + } v; + int lineno; + int col_offset; }; enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, @@ -186,211 +186,211 @@ Subscript_kind=22, Starred_kind=23, Name_kind=24, List_kind=25, Tuple_kind=26}; struct _expr { - enum _expr_kind kind; - union { - struct { - boolop_ty op; - asdl_seq *values; - } BoolOp; - - struct { - expr_ty left; - operator_ty op; - expr_ty right; - } BinOp; - - struct { - unaryop_ty op; - expr_ty operand; - } UnaryOp; - - struct { - arguments_ty args; - expr_ty body; - } Lambda; - - struct { - expr_ty test; - expr_ty body; - expr_ty orelse; - } IfExp; - - struct { - asdl_seq *keys; - asdl_seq *values; - } Dict; - - struct { - asdl_seq *elts; - } Set; - - struct { - expr_ty elt; - asdl_seq *generators; - } ListComp; - - struct { - expr_ty elt; - asdl_seq *generators; - } SetComp; - - struct { - expr_ty key; - expr_ty value; - asdl_seq *generators; - } DictComp; - - struct { - expr_ty elt; - asdl_seq *generators; - } GeneratorExp; - - struct { - expr_ty value; - } Yield; - - struct { - expr_ty value; - } YieldFrom; - - struct { - expr_ty left; - asdl_int_seq *ops; - asdl_seq *comparators; - } Compare; - - struct { - expr_ty func; - asdl_seq *args; - asdl_seq *keywords; - expr_ty starargs; - expr_ty kwargs; - } Call; - - struct { - object n; - } Num; - - struct { - string s; - } Str; - - struct { - bytes s; - } Bytes; - - struct { - singleton value; - } NameConstant; - - struct { - expr_ty value; - identifier attr; - expr_context_ty ctx; - } Attribute; - - struct { - expr_ty value; - slice_ty slice; - expr_context_ty ctx; - } Subscript; - - struct { - expr_ty value; - expr_context_ty ctx; - } Starred; - - struct { - identifier id; - expr_context_ty ctx; - } Name; - - struct { - asdl_seq *elts; - expr_context_ty ctx; - } List; - - struct { - asdl_seq *elts; - expr_context_ty ctx; - } Tuple; - - } v; - int lineno; - int col_offset; + enum _expr_kind kind; + union { + struct { + boolop_ty op; + asdl_seq *values; + } BoolOp; + + struct { + expr_ty left; + operator_ty op; + expr_ty right; + } BinOp; + + struct { + unaryop_ty op; + expr_ty operand; + } UnaryOp; + + struct { + arguments_ty args; + expr_ty body; + } Lambda; + + struct { + expr_ty test; + expr_ty body; + expr_ty orelse; + } IfExp; + + struct { + asdl_seq *keys; + asdl_seq *values; + } Dict; + + struct { + asdl_seq *elts; + } Set; + + struct { + expr_ty elt; + asdl_seq *generators; + } ListComp; + + struct { + expr_ty elt; + asdl_seq *generators; + } SetComp; + + struct { + expr_ty key; + expr_ty value; + asdl_seq *generators; + } DictComp; + + struct { + expr_ty elt; + asdl_seq *generators; + } GeneratorExp; + + struct { + expr_ty value; + } Yield; + + struct { + expr_ty value; + } YieldFrom; + + struct { + expr_ty left; + asdl_int_seq *ops; + asdl_seq *comparators; + } Compare; + + struct { + expr_ty func; + asdl_seq *args; + asdl_seq *keywords; + expr_ty starargs; + expr_ty kwargs; + } Call; + + struct { + object n; + } Num; + + struct { + string s; + } Str; + + struct { + bytes s; + } Bytes; + + struct { + singleton value; + } NameConstant; + + struct { + expr_ty value; + identifier attr; + expr_context_ty ctx; + } Attribute; + + struct { + expr_ty value; + slice_ty slice; + expr_context_ty ctx; + } Subscript; + + struct { + expr_ty value; + expr_context_ty ctx; + } Starred; + + struct { + identifier id; + expr_context_ty ctx; + } Name; + + struct { + asdl_seq *elts; + expr_context_ty ctx; + } List; + + struct { + asdl_seq *elts; + expr_context_ty ctx; + } Tuple; + + } v; + int lineno; + int col_offset; }; enum _slice_kind {Slice_kind=1, ExtSlice_kind=2, Index_kind=3}; struct _slice { - enum _slice_kind kind; - union { - struct { - expr_ty lower; - expr_ty upper; - expr_ty step; - } Slice; - - struct { - asdl_seq *dims; - } ExtSlice; - - struct { - expr_ty value; - } Index; - - } v; + enum _slice_kind kind; + union { + struct { + expr_ty lower; + expr_ty upper; + expr_ty step; + } Slice; + + struct { + asdl_seq *dims; + } ExtSlice; + + struct { + expr_ty value; + } Index; + + } v; }; struct _comprehension { - expr_ty target; - expr_ty iter; - asdl_seq *ifs; + expr_ty target; + expr_ty iter; + asdl_seq *ifs; }; enum _excepthandler_kind {ExceptHandler_kind=1}; struct _excepthandler { - enum _excepthandler_kind kind; - union { - struct { - expr_ty type; - identifier name; - asdl_seq *body; - } ExceptHandler; - - } v; - int lineno; - int col_offset; + enum _excepthandler_kind kind; + union { + struct { + expr_ty type; + identifier name; + asdl_seq *body; + } ExceptHandler; + + } v; + int lineno; + int col_offset; }; struct _arguments { - asdl_seq *args; - arg_ty vararg; - asdl_seq *kwonlyargs; - asdl_seq *kw_defaults; - arg_ty kwarg; - asdl_seq *defaults; + asdl_seq *args; + arg_ty vararg; + asdl_seq *kwonlyargs; + asdl_seq *kw_defaults; + arg_ty kwarg; + asdl_seq *defaults; }; struct _arg { - identifier arg; - expr_ty annotation; - int lineno; - int col_offset; + identifier arg; + expr_ty annotation; + int lineno; + int col_offset; }; struct _keyword { - identifier arg; - expr_ty value; + identifier arg; + expr_ty value; }; struct _alias { - identifier name; - identifier asname; + identifier name; + identifier asname; }; struct _withitem { - expr_ty context_expr; - expr_ty optional_vars; + expr_ty context_expr; + expr_ty optional_vars; }; diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -8,7 +8,7 @@ import asdl -TABSIZE = 8 +TABSIZE = 4 MAX_COL = 80 def get_c_type(name): diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -11,26 +11,26 @@ static PyTypeObject *Module_type; _Py_IDENTIFIER(body); static char *Module_fields[]={ - "body", + "body", }; static PyTypeObject *Interactive_type; static char *Interactive_fields[]={ - "body", + "body", }; static PyTypeObject *Expression_type; static char *Expression_fields[]={ - "body", + "body", }; static PyTypeObject *Suite_type; static char *Suite_fields[]={ - "body", + "body", }; static PyTypeObject *stmt_type; _Py_IDENTIFIER(lineno); _Py_IDENTIFIER(col_offset); static char *stmt_attributes[] = { - "lineno", - "col_offset", + "lineno", + "col_offset", }; static PyObject* ast2obj_stmt(void*); static PyTypeObject *FunctionDef_type; @@ -39,11 +39,11 @@ _Py_IDENTIFIER(decorator_list); _Py_IDENTIFIER(returns); static char *FunctionDef_fields[]={ - "name", - "args", - "body", - "decorator_list", - "returns", + "name", + "args", + "body", + "decorator_list", + "returns", }; static PyTypeObject *ClassDef_type; _Py_IDENTIFIER(bases); @@ -51,266 +51,266 @@ _Py_IDENTIFIER(starargs); _Py_IDENTIFIER(kwargs); static char *ClassDef_fields[]={ - "name", - "bases", - "keywords", - "starargs", - "kwargs", - "body", - "decorator_list", + "name", + "bases", + "keywords", + "starargs", + "kwargs", + "body", + "decorator_list", }; static PyTypeObject *Return_type; _Py_IDENTIFIER(value); static char *Return_fields[]={ - "value", + "value", }; static PyTypeObject *Delete_type; _Py_IDENTIFIER(targets); static char *Delete_fields[]={ - "targets", + "targets", }; static PyTypeObject *Assign_type; static char *Assign_fields[]={ - "targets", - "value", + "targets", + "value", }; static PyTypeObject *AugAssign_type; _Py_IDENTIFIER(target); _Py_IDENTIFIER(op); static char *AugAssign_fields[]={ - "target", - "op", - "value", + "target", + "op", + "value", }; static PyTypeObject *For_type; _Py_IDENTIFIER(iter); _Py_IDENTIFIER(orelse); static char *For_fields[]={ - "target", - "iter", - "body", - "orelse", + "target", + "iter", + "body", + "orelse", }; static PyTypeObject *While_type; _Py_IDENTIFIER(test); static char *While_fields[]={ - "test", - "body", - "orelse", + "test", + "body", + "orelse", }; static PyTypeObject *If_type; static char *If_fields[]={ - "test", - "body", - "orelse", + "test", + "body", + "orelse", }; static PyTypeObject *With_type; _Py_IDENTIFIER(items); static char *With_fields[]={ - "items", - "body", + "items", + "body", }; static PyTypeObject *Raise_type; _Py_IDENTIFIER(exc); _Py_IDENTIFIER(cause); static char *Raise_fields[]={ - "exc", - "cause", + "exc", + "cause", }; static PyTypeObject *Try_type; _Py_IDENTIFIER(handlers); _Py_IDENTIFIER(finalbody); static char *Try_fields[]={ - "body", - "handlers", - "orelse", - "finalbody", + "body", + "handlers", + "orelse", + "finalbody", }; static PyTypeObject *Assert_type; _Py_IDENTIFIER(msg); static char *Assert_fields[]={ - "test", - "msg", + "test", + "msg", }; static PyTypeObject *Import_type; _Py_IDENTIFIER(names); static char *Import_fields[]={ - "names", + "names", }; static PyTypeObject *ImportFrom_type; _Py_IDENTIFIER(module); _Py_IDENTIFIER(level); static char *ImportFrom_fields[]={ - "module", - "names", - "level", + "module", + "names", + "level", }; static PyTypeObject *Global_type; static char *Global_fields[]={ - "names", + "names", }; static PyTypeObject *Nonlocal_type; static char *Nonlocal_fields[]={ - "names", + "names", }; static PyTypeObject *Expr_type; static char *Expr_fields[]={ - "value", + "value", }; static PyTypeObject *Pass_type; static PyTypeObject *Break_type; static PyTypeObject *Continue_type; static PyTypeObject *expr_type; static char *expr_attributes[] = { - "lineno", - "col_offset", + "lineno", + "col_offset", }; static PyObject* ast2obj_expr(void*); static PyTypeObject *BoolOp_type; _Py_IDENTIFIER(values); static char *BoolOp_fields[]={ - "op", - "values", + "op", + "values", }; static PyTypeObject *BinOp_type; _Py_IDENTIFIER(left); _Py_IDENTIFIER(right); static char *BinOp_fields[]={ - "left", - "op", - "right", + "left", + "op", + "right", }; static PyTypeObject *UnaryOp_type; _Py_IDENTIFIER(operand); static char *UnaryOp_fields[]={ - "op", - "operand", + "op", + "operand", }; static PyTypeObject *Lambda_type; static char *Lambda_fields[]={ - "args", - "body", + "args", + "body", }; static PyTypeObject *IfExp_type; static char *IfExp_fields[]={ - "test", - "body", - "orelse", + "test", + "body", + "orelse", }; static PyTypeObject *Dict_type; _Py_IDENTIFIER(keys); static char *Dict_fields[]={ - "keys", - "values", + "keys", + "values", }; static PyTypeObject *Set_type; _Py_IDENTIFIER(elts); static char *Set_fields[]={ - "elts", + "elts", }; static PyTypeObject *ListComp_type; _Py_IDENTIFIER(elt); _Py_IDENTIFIER(generators); static char *ListComp_fields[]={ - "elt", - "generators", + "elt", + "generators", }; static PyTypeObject *SetComp_type; static char *SetComp_fields[]={ - "elt", - "generators", + "elt", + "generators", }; static PyTypeObject *DictComp_type; _Py_IDENTIFIER(key); static char *DictComp_fields[]={ - "key", - "value", - "generators", + "key", + "value", + "generators", }; static PyTypeObject *GeneratorExp_type; static char *GeneratorExp_fields[]={ - "elt", - "generators", + "elt", + "generators", }; static PyTypeObject *Yield_type; static char *Yield_fields[]={ - "value", + "value", }; static PyTypeObject *YieldFrom_type; static char *YieldFrom_fields[]={ - "value", + "value", }; static PyTypeObject *Compare_type; _Py_IDENTIFIER(ops); _Py_IDENTIFIER(comparators); static char *Compare_fields[]={ - "left", - "ops", - "comparators", + "left", + "ops", + "comparators", }; static PyTypeObject *Call_type; _Py_IDENTIFIER(func); static char *Call_fields[]={ - "func", - "args", - "keywords", - "starargs", - "kwargs", + "func", + "args", + "keywords", + "starargs", + "kwargs", }; static PyTypeObject *Num_type; _Py_IDENTIFIER(n); static char *Num_fields[]={ - "n", + "n", }; static PyTypeObject *Str_type; _Py_IDENTIFIER(s); static char *Str_fields[]={ - "s", + "s", }; static PyTypeObject *Bytes_type; static char *Bytes_fields[]={ - "s", + "s", }; static PyTypeObject *NameConstant_type; static char *NameConstant_fields[]={ - "value", + "value", }; static PyTypeObject *Ellipsis_type; static PyTypeObject *Attribute_type; _Py_IDENTIFIER(attr); _Py_IDENTIFIER(ctx); static char *Attribute_fields[]={ - "value", - "attr", - "ctx", + "value", + "attr", + "ctx", }; static PyTypeObject *Subscript_type; _Py_IDENTIFIER(slice); static char *Subscript_fields[]={ - "value", - "slice", - "ctx", + "value", + "slice", + "ctx", }; static PyTypeObject *Starred_type; static char *Starred_fields[]={ - "value", - "ctx", + "value", + "ctx", }; static PyTypeObject *Name_type; _Py_IDENTIFIER(id); static char *Name_fields[]={ - "id", - "ctx", + "id", + "ctx", }; static PyTypeObject *List_type; static char *List_fields[]={ - "elts", - "ctx", + "elts", + "ctx", }; static PyTypeObject *Tuple_type; static char *Tuple_fields[]={ - "elts", - "ctx", + "elts", + "ctx", }; static PyTypeObject *expr_context_type; static PyObject *Load_singleton, *Store_singleton, *Del_singleton, @@ -329,18 +329,18 @@ _Py_IDENTIFIER(upper); _Py_IDENTIFIER(step); static char *Slice_fields[]={ - "lower", - "upper", - "step", + "lower", + "upper", + "step", }; static PyTypeObject *ExtSlice_type; _Py_IDENTIFIER(dims); static char *ExtSlice_fields[]={ - "dims", + "dims", }; static PyTypeObject *Index_type; static char *Index_fields[]={ - "value", + "value", }; static PyTypeObject *boolop_type; static PyObject *And_singleton, *Or_singleton; @@ -392,22 +392,22 @@ static PyObject* ast2obj_comprehension(void*); _Py_IDENTIFIER(ifs); static char *comprehension_fields[]={ - "target", - "iter", - "ifs", + "target", + "iter", + "ifs", }; static PyTypeObject *excepthandler_type; static char *excepthandler_attributes[] = { - "lineno", - "col_offset", + "lineno", + "col_offset", }; static PyObject* ast2obj_excepthandler(void*); static PyTypeObject *ExceptHandler_type; _Py_IDENTIFIER(type); static char *ExceptHandler_fields[]={ - "type", - "name", - "body", + "type", + "name", + "body", }; static PyTypeObject *arguments_type; static PyObject* ast2obj_arguments(void*); @@ -417,45 +417,45 @@ _Py_IDENTIFIER(kwarg); _Py_IDENTIFIER(defaults); static char *arguments_fields[]={ - "args", - "vararg", - "kwonlyargs", - "kw_defaults", - "kwarg", - "defaults", + "args", + "vararg", + "kwonlyargs", + "kw_defaults", + "kwarg", + "defaults", }; static PyTypeObject *arg_type; static PyObject* ast2obj_arg(void*); static char *arg_attributes[] = { - "lineno", - "col_offset", + "lineno", + "col_offset", }; _Py_IDENTIFIER(arg); _Py_IDENTIFIER(annotation); static char *arg_fields[]={ - "arg", - "annotation", + "arg", + "annotation", }; static PyTypeObject *keyword_type; static PyObject* ast2obj_keyword(void*); static char *keyword_fields[]={ - "arg", - "value", + "arg", + "value", }; static PyTypeObject *alias_type; static PyObject* ast2obj_alias(void*); _Py_IDENTIFIER(asname); static char *alias_fields[]={ - "name", - "asname", + "name", + "asname", }; static PyTypeObject *withitem_type; static PyObject* ast2obj_withitem(void*); _Py_IDENTIFIER(context_expr); _Py_IDENTIFIER(optional_vars); static char *withitem_fields[]={ - "context_expr", - "optional_vars", + "context_expr", + "optional_vars", }; @@ -786,314 +786,312 @@ static int init_types(void) { - static int initialized; - if (initialized) return 1; - if (add_ast_fields() < 0) return 0; - mod_type = make_type("mod", &AST_type, NULL, 0); - if (!mod_type) return 0; - if (!add_attributes(mod_type, NULL, 0)) return 0; - Module_type = make_type("Module", mod_type, Module_fields, 1); - if (!Module_type) return 0; - Interactive_type = make_type("Interactive", mod_type, - Interactive_fields, 1); - if (!Interactive_type) return 0; - Expression_type = make_type("Expression", mod_type, Expression_fields, - 1); - if (!Expression_type) return 0; - Suite_type = make_type("Suite", mod_type, Suite_fields, 1); - if (!Suite_type) return 0; - stmt_type = make_type("stmt", &AST_type, NULL, 0); - if (!stmt_type) return 0; - if (!add_attributes(stmt_type, stmt_attributes, 2)) return 0; - FunctionDef_type = make_type("FunctionDef", stmt_type, - FunctionDef_fields, 5); - if (!FunctionDef_type) return 0; - ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 7); - if (!ClassDef_type) return 0; - Return_type = make_type("Return", stmt_type, Return_fields, 1); - if (!Return_type) return 0; - Delete_type = make_type("Delete", stmt_type, Delete_fields, 1); - if (!Delete_type) return 0; - Assign_type = make_type("Assign", stmt_type, Assign_fields, 2); - if (!Assign_type) return 0; - AugAssign_type = make_type("AugAssign", stmt_type, AugAssign_fields, 3); - if (!AugAssign_type) return 0; - For_type = make_type("For", stmt_type, For_fields, 4); - if (!For_type) return 0; - While_type = make_type("While", stmt_type, While_fields, 3); - if (!While_type) return 0; - If_type = make_type("If", stmt_type, If_fields, 3); - if (!If_type) return 0; - With_type = make_type("With", stmt_type, With_fields, 2); - if (!With_type) return 0; - Raise_type = make_type("Raise", stmt_type, Raise_fields, 2); - if (!Raise_type) return 0; - Try_type = make_type("Try", stmt_type, Try_fields, 4); - if (!Try_type) return 0; - Assert_type = make_type("Assert", stmt_type, Assert_fields, 2); - if (!Assert_type) return 0; - Import_type = make_type("Import", stmt_type, Import_fields, 1); - if (!Import_type) return 0; - ImportFrom_type = make_type("ImportFrom", stmt_type, ImportFrom_fields, - 3); - if (!ImportFrom_type) return 0; - Global_type = make_type("Global", stmt_type, Global_fields, 1); - if (!Global_type) return 0; - Nonlocal_type = make_type("Nonlocal", stmt_type, Nonlocal_fields, 1); - if (!Nonlocal_type) return 0; - Expr_type = make_type("Expr", stmt_type, Expr_fields, 1); - if (!Expr_type) return 0; - Pass_type = make_type("Pass", stmt_type, NULL, 0); - if (!Pass_type) return 0; - Break_type = make_type("Break", stmt_type, NULL, 0); - if (!Break_type) return 0; - Continue_type = make_type("Continue", stmt_type, NULL, 0); - if (!Continue_type) return 0; - expr_type = make_type("expr", &AST_type, NULL, 0); - if (!expr_type) return 0; - if (!add_attributes(expr_type, expr_attributes, 2)) return 0; - BoolOp_type = make_type("BoolOp", expr_type, BoolOp_fields, 2); - if (!BoolOp_type) return 0; - BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3); - if (!BinOp_type) return 0; - UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2); - if (!UnaryOp_type) return 0; - Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2); - if (!Lambda_type) return 0; - IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3); - if (!IfExp_type) return 0; - Dict_type = make_type("Dict", expr_type, Dict_fields, 2); - if (!Dict_type) return 0; - Set_type = make_type("Set", expr_type, Set_fields, 1); - if (!Set_type) return 0; - ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2); - if (!ListComp_type) return 0; - SetComp_type = make_type("SetComp", expr_type, SetComp_fields, 2); - if (!SetComp_type) return 0; - DictComp_type = make_type("DictComp", expr_type, DictComp_fields, 3); - if (!DictComp_type) return 0; - GeneratorExp_type = make_type("GeneratorExp", expr_type, - GeneratorExp_fields, 2); - if (!GeneratorExp_type) return 0; - Yield_type = make_type("Yield", expr_type, Yield_fields, 1); - if (!Yield_type) return 0; - YieldFrom_type = make_type("YieldFrom", expr_type, YieldFrom_fields, 1); - if (!YieldFrom_type) return 0; - Compare_type = make_type("Compare", expr_type, Compare_fields, 3); - if (!Compare_type) return 0; - Call_type = make_type("Call", expr_type, Call_fields, 5); - if (!Call_type) return 0; - Num_type = make_type("Num", expr_type, Num_fields, 1); - if (!Num_type) return 0; - Str_type = make_type("Str", expr_type, Str_fields, 1); - if (!Str_type) return 0; - Bytes_type = make_type("Bytes", expr_type, Bytes_fields, 1); - if (!Bytes_type) return 0; - NameConstant_type = make_type("NameConstant", expr_type, - NameConstant_fields, 1); - if (!NameConstant_type) return 0; - Ellipsis_type = make_type("Ellipsis", expr_type, NULL, 0); - if (!Ellipsis_type) return 0; - Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3); - if (!Attribute_type) return 0; - Subscript_type = make_type("Subscript", expr_type, Subscript_fields, 3); - if (!Subscript_type) return 0; - Starred_type = make_type("Starred", expr_type, Starred_fields, 2); - if (!Starred_type) return 0; - Name_type = make_type("Name", expr_type, Name_fields, 2); - if (!Name_type) return 0; - List_type = make_type("List", expr_type, List_fields, 2); - if (!List_type) return 0; - Tuple_type = make_type("Tuple", expr_type, Tuple_fields, 2); - if (!Tuple_type) return 0; - expr_context_type = make_type("expr_context", &AST_type, NULL, 0); - if (!expr_context_type) return 0; - if (!add_attributes(expr_context_type, NULL, 0)) return 0; - Load_type = make_type("Load", expr_context_type, NULL, 0); - if (!Load_type) return 0; - Load_singleton = PyType_GenericNew(Load_type, NULL, NULL); - if (!Load_singleton) return 0; - Store_type = make_type("Store", expr_context_type, NULL, 0); - if (!Store_type) return 0; - Store_singleton = PyType_GenericNew(Store_type, NULL, NULL); - if (!Store_singleton) return 0; - Del_type = make_type("Del", expr_context_type, NULL, 0); - if (!Del_type) return 0; - Del_singleton = PyType_GenericNew(Del_type, NULL, NULL); - if (!Del_singleton) return 0; - AugLoad_type = make_type("AugLoad", expr_context_type, NULL, 0); - if (!AugLoad_type) return 0; - AugLoad_singleton = PyType_GenericNew(AugLoad_type, NULL, NULL); - if (!AugLoad_singleton) return 0; - AugStore_type = make_type("AugStore", expr_context_type, NULL, 0); - if (!AugStore_type) return 0; - AugStore_singleton = PyType_GenericNew(AugStore_type, NULL, NULL); - if (!AugStore_singleton) return 0; - Param_type = make_type("Param", expr_context_type, NULL, 0); - if (!Param_type) return 0; - Param_singleton = PyType_GenericNew(Param_type, NULL, NULL); - if (!Param_singleton) return 0; - slice_type = make_type("slice", &AST_type, NULL, 0); - if (!slice_type) return 0; - if (!add_attributes(slice_type, NULL, 0)) return 0; - Slice_type = make_type("Slice", slice_type, Slice_fields, 3); - if (!Slice_type) return 0; - ExtSlice_type = make_type("ExtSlice", slice_type, ExtSlice_fields, 1); - if (!ExtSlice_type) return 0; - Index_type = make_type("Index", slice_type, Index_fields, 1); - if (!Index_type) return 0; - boolop_type = make_type("boolop", &AST_type, NULL, 0); - if (!boolop_type) return 0; - if (!add_attributes(boolop_type, NULL, 0)) return 0; - And_type = make_type("And", boolop_type, NULL, 0); - if (!And_type) return 0; - And_singleton = PyType_GenericNew(And_type, NULL, NULL); - if (!And_singleton) return 0; - Or_type = make_type("Or", boolop_type, NULL, 0); - if (!Or_type) return 0; - Or_singleton = PyType_GenericNew(Or_type, NULL, NULL); - if (!Or_singleton) return 0; - operator_type = make_type("operator", &AST_type, NULL, 0); - if (!operator_type) return 0; - if (!add_attributes(operator_type, NULL, 0)) return 0; - Add_type = make_type("Add", operator_type, NULL, 0); - if (!Add_type) return 0; - Add_singleton = PyType_GenericNew(Add_type, NULL, NULL); - if (!Add_singleton) return 0; - Sub_type = make_type("Sub", operator_type, NULL, 0); - if (!Sub_type) return 0; - Sub_singleton = PyType_GenericNew(Sub_type, NULL, NULL); - if (!Sub_singleton) return 0; - Mult_type = make_type("Mult", operator_type, NULL, 0); - if (!Mult_type) return 0; - Mult_singleton = PyType_GenericNew(Mult_type, NULL, NULL); - if (!Mult_singleton) return 0; - Div_type = make_type("Div", operator_type, NULL, 0); - if (!Div_type) return 0; - Div_singleton = PyType_GenericNew(Div_type, NULL, NULL); - if (!Div_singleton) return 0; - Mod_type = make_type("Mod", operator_type, NULL, 0); - if (!Mod_type) return 0; - Mod_singleton = PyType_GenericNew(Mod_type, NULL, NULL); - if (!Mod_singleton) return 0; - Pow_type = make_type("Pow", operator_type, NULL, 0); - if (!Pow_type) return 0; - Pow_singleton = PyType_GenericNew(Pow_type, NULL, NULL); - if (!Pow_singleton) return 0; - LShift_type = make_type("LShift", operator_type, NULL, 0); - if (!LShift_type) return 0; - LShift_singleton = PyType_GenericNew(LShift_type, NULL, NULL); - if (!LShift_singleton) return 0; - RShift_type = make_type("RShift", operator_type, NULL, 0); - if (!RShift_type) return 0; - RShift_singleton = PyType_GenericNew(RShift_type, NULL, NULL); - if (!RShift_singleton) return 0; - BitOr_type = make_type("BitOr", operator_type, NULL, 0); - if (!BitOr_type) return 0; - BitOr_singleton = PyType_GenericNew(BitOr_type, NULL, NULL); - if (!BitOr_singleton) return 0; - BitXor_type = make_type("BitXor", operator_type, NULL, 0); - if (!BitXor_type) return 0; - BitXor_singleton = PyType_GenericNew(BitXor_type, NULL, NULL); - if (!BitXor_singleton) return 0; - BitAnd_type = make_type("BitAnd", operator_type, NULL, 0); - if (!BitAnd_type) return 0; - BitAnd_singleton = PyType_GenericNew(BitAnd_type, NULL, NULL); - if (!BitAnd_singleton) return 0; - FloorDiv_type = make_type("FloorDiv", operator_type, NULL, 0); - if (!FloorDiv_type) return 0; - FloorDiv_singleton = PyType_GenericNew(FloorDiv_type, NULL, NULL); - if (!FloorDiv_singleton) return 0; - unaryop_type = make_type("unaryop", &AST_type, NULL, 0); - if (!unaryop_type) return 0; - if (!add_attributes(unaryop_type, NULL, 0)) return 0; - Invert_type = make_type("Invert", unaryop_type, NULL, 0); - if (!Invert_type) return 0; - Invert_singleton = PyType_GenericNew(Invert_type, NULL, NULL); - if (!Invert_singleton) return 0; - Not_type = make_type("Not", unaryop_type, NULL, 0); - if (!Not_type) return 0; - Not_singleton = PyType_GenericNew(Not_type, NULL, NULL); - if (!Not_singleton) return 0; - UAdd_type = make_type("UAdd", unaryop_type, NULL, 0); - if (!UAdd_type) return 0; - UAdd_singleton = PyType_GenericNew(UAdd_type, NULL, NULL); - if (!UAdd_singleton) return 0; - USub_type = make_type("USub", unaryop_type, NULL, 0); - if (!USub_type) return 0; - USub_singleton = PyType_GenericNew(USub_type, NULL, NULL); - if (!USub_singleton) return 0; - cmpop_type = make_type("cmpop", &AST_type, NULL, 0); - if (!cmpop_type) return 0; - if (!add_attributes(cmpop_type, NULL, 0)) return 0; - Eq_type = make_type("Eq", cmpop_type, NULL, 0); - if (!Eq_type) return 0; - Eq_singleton = PyType_GenericNew(Eq_type, NULL, NULL); - if (!Eq_singleton) return 0; - NotEq_type = make_type("NotEq", cmpop_type, NULL, 0); - if (!NotEq_type) return 0; - NotEq_singleton = PyType_GenericNew(NotEq_type, NULL, NULL); - if (!NotEq_singleton) return 0; - Lt_type = make_type("Lt", cmpop_type, NULL, 0); - if (!Lt_type) return 0; - Lt_singleton = PyType_GenericNew(Lt_type, NULL, NULL); - if (!Lt_singleton) return 0; - LtE_type = make_type("LtE", cmpop_type, NULL, 0); - if (!LtE_type) return 0; - LtE_singleton = PyType_GenericNew(LtE_type, NULL, NULL); - if (!LtE_singleton) return 0; - Gt_type = make_type("Gt", cmpop_type, NULL, 0); - if (!Gt_type) return 0; - Gt_singleton = PyType_GenericNew(Gt_type, NULL, NULL); - if (!Gt_singleton) return 0; - GtE_type = make_type("GtE", cmpop_type, NULL, 0); - if (!GtE_type) return 0; - GtE_singleton = PyType_GenericNew(GtE_type, NULL, NULL); - if (!GtE_singleton) return 0; - Is_type = make_type("Is", cmpop_type, NULL, 0); - if (!Is_type) return 0; - Is_singleton = PyType_GenericNew(Is_type, NULL, NULL); - if (!Is_singleton) return 0; - IsNot_type = make_type("IsNot", cmpop_type, NULL, 0); - if (!IsNot_type) return 0; - IsNot_singleton = PyType_GenericNew(IsNot_type, NULL, NULL); - if (!IsNot_singleton) return 0; - In_type = make_type("In", cmpop_type, NULL, 0); - if (!In_type) return 0; - In_singleton = PyType_GenericNew(In_type, NULL, NULL); - if (!In_singleton) return 0; - NotIn_type = make_type("NotIn", cmpop_type, NULL, 0); - if (!NotIn_type) return 0; - NotIn_singleton = PyType_GenericNew(NotIn_type, NULL, NULL); - if (!NotIn_singleton) return 0; - comprehension_type = make_type("comprehension", &AST_type, - comprehension_fields, 3); - if (!comprehension_type) return 0; - if (!add_attributes(comprehension_type, NULL, 0)) return 0; - excepthandler_type = make_type("excepthandler", &AST_type, NULL, 0); - if (!excepthandler_type) return 0; - if (!add_attributes(excepthandler_type, excepthandler_attributes, 2)) - return 0; - ExceptHandler_type = make_type("ExceptHandler", excepthandler_type, - ExceptHandler_fields, 3); - if (!ExceptHandler_type) return 0; - arguments_type = make_type("arguments", &AST_type, arguments_fields, 6); - if (!arguments_type) return 0; - if (!add_attributes(arguments_type, NULL, 0)) return 0; - arg_type = make_type("arg", &AST_type, arg_fields, 2); - if (!arg_type) return 0; - if (!add_attributes(arg_type, arg_attributes, 2)) return 0; - keyword_type = make_type("keyword", &AST_type, keyword_fields, 2); - if (!keyword_type) return 0; - if (!add_attributes(keyword_type, NULL, 0)) return 0; - alias_type = make_type("alias", &AST_type, alias_fields, 2); - if (!alias_type) return 0; - if (!add_attributes(alias_type, NULL, 0)) return 0; - withitem_type = make_type("withitem", &AST_type, withitem_fields, 2); - if (!withitem_type) return 0; - if (!add_attributes(withitem_type, NULL, 0)) return 0; - initialized = 1; - return 1; + static int initialized; + if (initialized) return 1; + if (add_ast_fields() < 0) return 0; + mod_type = make_type("mod", &AST_type, NULL, 0); + if (!mod_type) return 0; + if (!add_attributes(mod_type, NULL, 0)) return 0; + Module_type = make_type("Module", mod_type, Module_fields, 1); + if (!Module_type) return 0; + Interactive_type = make_type("Interactive", mod_type, Interactive_fields, + 1); + if (!Interactive_type) return 0; + Expression_type = make_type("Expression", mod_type, Expression_fields, 1); + if (!Expression_type) return 0; + Suite_type = make_type("Suite", mod_type, Suite_fields, 1); + if (!Suite_type) return 0; + stmt_type = make_type("stmt", &AST_type, NULL, 0); + if (!stmt_type) return 0; + if (!add_attributes(stmt_type, stmt_attributes, 2)) return 0; + FunctionDef_type = make_type("FunctionDef", stmt_type, FunctionDef_fields, + 5); + if (!FunctionDef_type) return 0; + ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 7); + if (!ClassDef_type) return 0; + Return_type = make_type("Return", stmt_type, Return_fields, 1); + if (!Return_type) return 0; + Delete_type = make_type("Delete", stmt_type, Delete_fields, 1); + if (!Delete_type) return 0; + Assign_type = make_type("Assign", stmt_type, Assign_fields, 2); + if (!Assign_type) return 0; + AugAssign_type = make_type("AugAssign", stmt_type, AugAssign_fields, 3); + if (!AugAssign_type) return 0; + For_type = make_type("For", stmt_type, For_fields, 4); + if (!For_type) return 0; + While_type = make_type("While", stmt_type, While_fields, 3); + if (!While_type) return 0; + If_type = make_type("If", stmt_type, If_fields, 3); + if (!If_type) return 0; + With_type = make_type("With", stmt_type, With_fields, 2); + if (!With_type) return 0; + Raise_type = make_type("Raise", stmt_type, Raise_fields, 2); + if (!Raise_type) return 0; + Try_type = make_type("Try", stmt_type, Try_fields, 4); + if (!Try_type) return 0; + Assert_type = make_type("Assert", stmt_type, Assert_fields, 2); + if (!Assert_type) return 0; + Import_type = make_type("Import", stmt_type, Import_fields, 1); + if (!Import_type) return 0; + ImportFrom_type = make_type("ImportFrom", stmt_type, ImportFrom_fields, 3); + if (!ImportFrom_type) return 0; + Global_type = make_type("Global", stmt_type, Global_fields, 1); + if (!Global_type) return 0; + Nonlocal_type = make_type("Nonlocal", stmt_type, Nonlocal_fields, 1); + if (!Nonlocal_type) return 0; + Expr_type = make_type("Expr", stmt_type, Expr_fields, 1); + if (!Expr_type) return 0; + Pass_type = make_type("Pass", stmt_type, NULL, 0); + if (!Pass_type) return 0; + Break_type = make_type("Break", stmt_type, NULL, 0); + if (!Break_type) return 0; + Continue_type = make_type("Continue", stmt_type, NULL, 0); + if (!Continue_type) return 0; + expr_type = make_type("expr", &AST_type, NULL, 0); + if (!expr_type) return 0; + if (!add_attributes(expr_type, expr_attributes, 2)) return 0; + BoolOp_type = make_type("BoolOp", expr_type, BoolOp_fields, 2); + if (!BoolOp_type) return 0; + BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3); + if (!BinOp_type) return 0; + UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2); + if (!UnaryOp_type) return 0; + Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2); + if (!Lambda_type) return 0; + IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3); + if (!IfExp_type) return 0; + Dict_type = make_type("Dict", expr_type, Dict_fields, 2); + if (!Dict_type) return 0; + Set_type = make_type("Set", expr_type, Set_fields, 1); + if (!Set_type) return 0; + ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2); + if (!ListComp_type) return 0; + SetComp_type = make_type("SetComp", expr_type, SetComp_fields, 2); + if (!SetComp_type) return 0; + DictComp_type = make_type("DictComp", expr_type, DictComp_fields, 3); + if (!DictComp_type) return 0; + GeneratorExp_type = make_type("GeneratorExp", expr_type, + GeneratorExp_fields, 2); + if (!GeneratorExp_type) return 0; + Yield_type = make_type("Yield", expr_type, Yield_fields, 1); + if (!Yield_type) return 0; + YieldFrom_type = make_type("YieldFrom", expr_type, YieldFrom_fields, 1); + if (!YieldFrom_type) return 0; + Compare_type = make_type("Compare", expr_type, Compare_fields, 3); + if (!Compare_type) return 0; + Call_type = make_type("Call", expr_type, Call_fields, 5); + if (!Call_type) return 0; + Num_type = make_type("Num", expr_type, Num_fields, 1); + if (!Num_type) return 0; + Str_type = make_type("Str", expr_type, Str_fields, 1); + if (!Str_type) return 0; + Bytes_type = make_type("Bytes", expr_type, Bytes_fields, 1); + if (!Bytes_type) return 0; + NameConstant_type = make_type("NameConstant", expr_type, + NameConstant_fields, 1); + if (!NameConstant_type) return 0; + Ellipsis_type = make_type("Ellipsis", expr_type, NULL, 0); + if (!Ellipsis_type) return 0; + Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3); + if (!Attribute_type) return 0; + Subscript_type = make_type("Subscript", expr_type, Subscript_fields, 3); + if (!Subscript_type) return 0; + Starred_type = make_type("Starred", expr_type, Starred_fields, 2); + if (!Starred_type) return 0; + Name_type = make_type("Name", expr_type, Name_fields, 2); + if (!Name_type) return 0; + List_type = make_type("List", expr_type, List_fields, 2); + if (!List_type) return 0; + Tuple_type = make_type("Tuple", expr_type, Tuple_fields, 2); + if (!Tuple_type) return 0; + expr_context_type = make_type("expr_context", &AST_type, NULL, 0); + if (!expr_context_type) return 0; + if (!add_attributes(expr_context_type, NULL, 0)) return 0; + Load_type = make_type("Load", expr_context_type, NULL, 0); + if (!Load_type) return 0; + Load_singleton = PyType_GenericNew(Load_type, NULL, NULL); + if (!Load_singleton) return 0; + Store_type = make_type("Store", expr_context_type, NULL, 0); + if (!Store_type) return 0; + Store_singleton = PyType_GenericNew(Store_type, NULL, NULL); + if (!Store_singleton) return 0; + Del_type = make_type("Del", expr_context_type, NULL, 0); + if (!Del_type) return 0; + Del_singleton = PyType_GenericNew(Del_type, NULL, NULL); + if (!Del_singleton) return 0; + AugLoad_type = make_type("AugLoad", expr_context_type, NULL, 0); + if (!AugLoad_type) return 0; + AugLoad_singleton = PyType_GenericNew(AugLoad_type, NULL, NULL); + if (!AugLoad_singleton) return 0; + AugStore_type = make_type("AugStore", expr_context_type, NULL, 0); + if (!AugStore_type) return 0; + AugStore_singleton = PyType_GenericNew(AugStore_type, NULL, NULL); + if (!AugStore_singleton) return 0; + Param_type = make_type("Param", expr_context_type, NULL, 0); + if (!Param_type) return 0; + Param_singleton = PyType_GenericNew(Param_type, NULL, NULL); + if (!Param_singleton) return 0; + slice_type = make_type("slice", &AST_type, NULL, 0); + if (!slice_type) return 0; + if (!add_attributes(slice_type, NULL, 0)) return 0; + Slice_type = make_type("Slice", slice_type, Slice_fields, 3); + if (!Slice_type) return 0; + ExtSlice_type = make_type("ExtSlice", slice_type, ExtSlice_fields, 1); + if (!ExtSlice_type) return 0; + Index_type = make_type("Index", slice_type, Index_fields, 1); + if (!Index_type) return 0; + boolop_type = make_type("boolop", &AST_type, NULL, 0); + if (!boolop_type) return 0; + if (!add_attributes(boolop_type, NULL, 0)) return 0; + And_type = make_type("And", boolop_type, NULL, 0); + if (!And_type) return 0; + And_singleton = PyType_GenericNew(And_type, NULL, NULL); + if (!And_singleton) return 0; + Or_type = make_type("Or", boolop_type, NULL, 0); + if (!Or_type) return 0; + Or_singleton = PyType_GenericNew(Or_type, NULL, NULL); + if (!Or_singleton) return 0; + operator_type = make_type("operator", &AST_type, NULL, 0); + if (!operator_type) return 0; + if (!add_attributes(operator_type, NULL, 0)) return 0; + Add_type = make_type("Add", operator_type, NULL, 0); + if (!Add_type) return 0; + Add_singleton = PyType_GenericNew(Add_type, NULL, NULL); + if (!Add_singleton) return 0; + Sub_type = make_type("Sub", operator_type, NULL, 0); + if (!Sub_type) return 0; + Sub_singleton = PyType_GenericNew(Sub_type, NULL, NULL); + if (!Sub_singleton) return 0; + Mult_type = make_type("Mult", operator_type, NULL, 0); + if (!Mult_type) return 0; + Mult_singleton = PyType_GenericNew(Mult_type, NULL, NULL); + if (!Mult_singleton) return 0; + Div_type = make_type("Div", operator_type, NULL, 0); + if (!Div_type) return 0; + Div_singleton = PyType_GenericNew(Div_type, NULL, NULL); + if (!Div_singleton) return 0; + Mod_type = make_type("Mod", operator_type, NULL, 0); + if (!Mod_type) return 0; + Mod_singleton = PyType_GenericNew(Mod_type, NULL, NULL); + if (!Mod_singleton) return 0; + Pow_type = make_type("Pow", operator_type, NULL, 0); + if (!Pow_type) return 0; + Pow_singleton = PyType_GenericNew(Pow_type, NULL, NULL); + if (!Pow_singleton) return 0; + LShift_type = make_type("LShift", operator_type, NULL, 0); + if (!LShift_type) return 0; + LShift_singleton = PyType_GenericNew(LShift_type, NULL, NULL); + if (!LShift_singleton) return 0; + RShift_type = make_type("RShift", operator_type, NULL, 0); + if (!RShift_type) return 0; + RShift_singleton = PyType_GenericNew(RShift_type, NULL, NULL); + if (!RShift_singleton) return 0; + BitOr_type = make_type("BitOr", operator_type, NULL, 0); + if (!BitOr_type) return 0; + BitOr_singleton = PyType_GenericNew(BitOr_type, NULL, NULL); + if (!BitOr_singleton) return 0; + BitXor_type = make_type("BitXor", operator_type, NULL, 0); + if (!BitXor_type) return 0; + BitXor_singleton = PyType_GenericNew(BitXor_type, NULL, NULL); + if (!BitXor_singleton) return 0; + BitAnd_type = make_type("BitAnd", operator_type, NULL, 0); + if (!BitAnd_type) return 0; + BitAnd_singleton = PyType_GenericNew(BitAnd_type, NULL, NULL); + if (!BitAnd_singleton) return 0; + FloorDiv_type = make_type("FloorDiv", operator_type, NULL, 0); + if (!FloorDiv_type) return 0; + FloorDiv_singleton = PyType_GenericNew(FloorDiv_type, NULL, NULL); + if (!FloorDiv_singleton) return 0; + unaryop_type = make_type("unaryop", &AST_type, NULL, 0); + if (!unaryop_type) return 0; + if (!add_attributes(unaryop_type, NULL, 0)) return 0; + Invert_type = make_type("Invert", unaryop_type, NULL, 0); + if (!Invert_type) return 0; + Invert_singleton = PyType_GenericNew(Invert_type, NULL, NULL); + if (!Invert_singleton) return 0; + Not_type = make_type("Not", unaryop_type, NULL, 0); + if (!Not_type) return 0; + Not_singleton = PyType_GenericNew(Not_type, NULL, NULL); + if (!Not_singleton) return 0; + UAdd_type = make_type("UAdd", unaryop_type, NULL, 0); + if (!UAdd_type) return 0; + UAdd_singleton = PyType_GenericNew(UAdd_type, NULL, NULL); + if (!UAdd_singleton) return 0; + USub_type = make_type("USub", unaryop_type, NULL, 0); + if (!USub_type) return 0; + USub_singleton = PyType_GenericNew(USub_type, NULL, NULL); + if (!USub_singleton) return 0; + cmpop_type = make_type("cmpop", &AST_type, NULL, 0); + if (!cmpop_type) return 0; + if (!add_attributes(cmpop_type, NULL, 0)) return 0; + Eq_type = make_type("Eq", cmpop_type, NULL, 0); + if (!Eq_type) return 0; + Eq_singleton = PyType_GenericNew(Eq_type, NULL, NULL); + if (!Eq_singleton) return 0; + NotEq_type = make_type("NotEq", cmpop_type, NULL, 0); + if (!NotEq_type) return 0; + NotEq_singleton = PyType_GenericNew(NotEq_type, NULL, NULL); + if (!NotEq_singleton) return 0; + Lt_type = make_type("Lt", cmpop_type, NULL, 0); + if (!Lt_type) return 0; + Lt_singleton = PyType_GenericNew(Lt_type, NULL, NULL); + if (!Lt_singleton) return 0; + LtE_type = make_type("LtE", cmpop_type, NULL, 0); + if (!LtE_type) return 0; + LtE_singleton = PyType_GenericNew(LtE_type, NULL, NULL); + if (!LtE_singleton) return 0; + Gt_type = make_type("Gt", cmpop_type, NULL, 0); + if (!Gt_type) return 0; + Gt_singleton = PyType_GenericNew(Gt_type, NULL, NULL); + if (!Gt_singleton) return 0; + GtE_type = make_type("GtE", cmpop_type, NULL, 0); + if (!GtE_type) return 0; + GtE_singleton = PyType_GenericNew(GtE_type, NULL, NULL); + if (!GtE_singleton) return 0; + Is_type = make_type("Is", cmpop_type, NULL, 0); + if (!Is_type) return 0; + Is_singleton = PyType_GenericNew(Is_type, NULL, NULL); + if (!Is_singleton) return 0; + IsNot_type = make_type("IsNot", cmpop_type, NULL, 0); + if (!IsNot_type) return 0; + IsNot_singleton = PyType_GenericNew(IsNot_type, NULL, NULL); + if (!IsNot_singleton) return 0; + In_type = make_type("In", cmpop_type, NULL, 0); + if (!In_type) return 0; + In_singleton = PyType_GenericNew(In_type, NULL, NULL); + if (!In_singleton) return 0; + NotIn_type = make_type("NotIn", cmpop_type, NULL, 0); + if (!NotIn_type) return 0; + NotIn_singleton = PyType_GenericNew(NotIn_type, NULL, NULL); + if (!NotIn_singleton) return 0; + comprehension_type = make_type("comprehension", &AST_type, + comprehension_fields, 3); + if (!comprehension_type) return 0; + if (!add_attributes(comprehension_type, NULL, 0)) return 0; + excepthandler_type = make_type("excepthandler", &AST_type, NULL, 0); + if (!excepthandler_type) return 0; + if (!add_attributes(excepthandler_type, excepthandler_attributes, 2)) + return 0; + ExceptHandler_type = make_type("ExceptHandler", excepthandler_type, + ExceptHandler_fields, 3); + if (!ExceptHandler_type) return 0; + arguments_type = make_type("arguments", &AST_type, arguments_fields, 6); + if (!arguments_type) return 0; + if (!add_attributes(arguments_type, NULL, 0)) return 0; + arg_type = make_type("arg", &AST_type, arg_fields, 2); + if (!arg_type) return 0; + if (!add_attributes(arg_type, arg_attributes, 2)) return 0; + keyword_type = make_type("keyword", &AST_type, keyword_fields, 2); + if (!keyword_type) return 0; + if (!add_attributes(keyword_type, NULL, 0)) return 0; + alias_type = make_type("alias", &AST_type, alias_fields, 2); + if (!alias_type) return 0; + if (!add_attributes(alias_type, NULL, 0)) return 0; + withitem_type = make_type("withitem", &AST_type, withitem_fields, 2); + if (!withitem_type) return 0; + if (!add_attributes(withitem_type, NULL, 0)) return 0; + initialized = 1; + return 1; } static int obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena); @@ -1119,54 +1117,54 @@ mod_ty Module(asdl_seq * body, PyArena *arena) { - mod_ty p; - p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Module_kind; - p->v.Module.body = body; - return p; + mod_ty p; + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Module_kind; + p->v.Module.body = body; + return p; } mod_ty Interactive(asdl_seq * body, PyArena *arena) { - mod_ty p; - p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Interactive_kind; - p->v.Interactive.body = body; - return p; + mod_ty p; + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Interactive_kind; + p->v.Interactive.body = body; + return p; } mod_ty Expression(expr_ty body, PyArena *arena) { - mod_ty p; - if (!body) { - PyErr_SetString(PyExc_ValueError, - "field body is required for Expression"); - return NULL; - } - p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Expression_kind; - p->v.Expression.body = body; - return p; + mod_ty p; + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for Expression"); + return NULL; + } + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Expression_kind; + p->v.Expression.body = body; + return p; } mod_ty Suite(asdl_seq * body, PyArena *arena) { - mod_ty p; - p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Suite_kind; - p->v.Suite.body = body; - return p; + mod_ty p; + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Suite_kind; + p->v.Suite.body = body; + return p; } stmt_ty @@ -1174,29 +1172,29 @@ decorator_list, expr_ty returns, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!name) { - PyErr_SetString(PyExc_ValueError, - "field name is required for FunctionDef"); - return NULL; - } - if (!args) { - PyErr_SetString(PyExc_ValueError, - "field args is required for FunctionDef"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = FunctionDef_kind; - p->v.FunctionDef.name = name; - p->v.FunctionDef.args = args; - p->v.FunctionDef.body = body; - p->v.FunctionDef.decorator_list = decorator_list; - p->v.FunctionDef.returns = returns; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field name is required for FunctionDef"); + return NULL; + } + if (!args) { + PyErr_SetString(PyExc_ValueError, + "field args is required for FunctionDef"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = FunctionDef_kind; + p->v.FunctionDef.name = name; + p->v.FunctionDef.args = args; + p->v.FunctionDef.body = body; + p->v.FunctionDef.decorator_list = decorator_list; + p->v.FunctionDef.returns = returns; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty @@ -1204,5763 +1202,5751 @@ starargs, expr_ty kwargs, asdl_seq * body, asdl_seq * decorator_list, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!name) { - PyErr_SetString(PyExc_ValueError, - "field name is required for ClassDef"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ClassDef_kind; - p->v.ClassDef.name = name; - p->v.ClassDef.bases = bases; - p->v.ClassDef.keywords = keywords; - p->v.ClassDef.starargs = starargs; - p->v.ClassDef.kwargs = kwargs; - p->v.ClassDef.body = body; - p->v.ClassDef.decorator_list = decorator_list; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field name is required for ClassDef"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ClassDef_kind; + p->v.ClassDef.name = name; + p->v.ClassDef.bases = bases; + p->v.ClassDef.keywords = keywords; + p->v.ClassDef.starargs = starargs; + p->v.ClassDef.kwargs = kwargs; + p->v.ClassDef.body = body; + p->v.ClassDef.decorator_list = decorator_list; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Return(expr_ty value, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Return_kind; - p->v.Return.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Return_kind; + p->v.Return.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Delete(asdl_seq * targets, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Delete_kind; - p->v.Delete.targets = targets; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Delete_kind; + p->v.Delete.targets = targets; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Assign(asdl_seq * targets, expr_ty value, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Assign"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Assign_kind; - p->v.Assign.targets = targets; - p->v.Assign.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Assign"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Assign_kind; + p->v.Assign.targets = targets; + p->v.Assign.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!target) { - PyErr_SetString(PyExc_ValueError, - "field target is required for AugAssign"); - return NULL; - } - if (!op) { - PyErr_SetString(PyExc_ValueError, - "field op is required for AugAssign"); - return NULL; - } - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for AugAssign"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = AugAssign_kind; - p->v.AugAssign.target = target; - p->v.AugAssign.op = op; - p->v.AugAssign.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!target) { + PyErr_SetString(PyExc_ValueError, + "field target is required for AugAssign"); + return NULL; + } + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for AugAssign"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for AugAssign"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = AugAssign_kind; + p->v.AugAssign.target = target; + p->v.AugAssign.op = op; + p->v.AugAssign.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!target) { - PyErr_SetString(PyExc_ValueError, - "field target is required for For"); - return NULL; - } - if (!iter) { - PyErr_SetString(PyExc_ValueError, - "field iter is required for For"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = For_kind; - p->v.For.target = target; - p->v.For.iter = iter; - p->v.For.body = body; - p->v.For.orelse = orelse; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!target) { + PyErr_SetString(PyExc_ValueError, + "field target is required for For"); + return NULL; + } + if (!iter) { + PyErr_SetString(PyExc_ValueError, + "field iter is required for For"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = For_kind; + p->v.For.target = target; + p->v.For.iter = iter; + p->v.For.body = body; + p->v.For.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!test) { - PyErr_SetString(PyExc_ValueError, - "field test is required for While"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = While_kind; - p->v.While.test = test; - p->v.While.body = body; - p->v.While.orelse = orelse; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for While"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = While_kind; + p->v.While.test = test; + p->v.While.body = body; + p->v.While.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!test) { - PyErr_SetString(PyExc_ValueError, - "field test is required for If"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = If_kind; - p->v.If.test = test; - p->v.If.body = body; - p->v.If.orelse = orelse; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for If"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = If_kind; + p->v.If.test = test; + p->v.If.body = body; + p->v.If.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty With(asdl_seq * items, asdl_seq * body, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = With_kind; - p->v.With.items = items; - p->v.With.body = body; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = With_kind; + p->v.With.items = items; + p->v.With.body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Raise_kind; - p->v.Raise.exc = exc; - p->v.Raise.cause = cause; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Raise_kind; + p->v.Raise.exc = exc; + p->v.Raise.cause = cause; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Try(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, asdl_seq * finalbody, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Try_kind; - p->v.Try.body = body; - p->v.Try.handlers = handlers; - p->v.Try.orelse = orelse; - p->v.Try.finalbody = finalbody; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Try_kind; + p->v.Try.body = body; + p->v.Try.handlers = handlers; + p->v.Try.orelse = orelse; + p->v.Try.finalbody = finalbody; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!test) { - PyErr_SetString(PyExc_ValueError, - "field test is required for Assert"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Assert_kind; - p->v.Assert.test = test; - p->v.Assert.msg = msg; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for Assert"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Assert_kind; + p->v.Assert.test = test; + p->v.Assert.msg = msg; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Import(asdl_seq * names, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Import_kind; - p->v.Import.names = names; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Import_kind; + p->v.Import.names = names; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty ImportFrom(identifier module, asdl_seq * names, int level, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ImportFrom_kind; - p->v.ImportFrom.module = module; - p->v.ImportFrom.names = names; - p->v.ImportFrom.level = level; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ImportFrom_kind; + p->v.ImportFrom.module = module; + p->v.ImportFrom.names = names; + p->v.ImportFrom.level = level; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Global(asdl_seq * names, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Global_kind; - p->v.Global.names = names; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Global_kind; + p->v.Global.names = names; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Nonlocal(asdl_seq * names, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Nonlocal_kind; - p->v.Nonlocal.names = names; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Nonlocal_kind; + p->v.Nonlocal.names = names; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Expr(expr_ty value, int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Expr"); - return NULL; - } - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Expr_kind; - p->v.Expr.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Expr"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Expr_kind; + p->v.Expr.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Pass(int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Pass_kind; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Pass_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Break(int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Break_kind; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Break_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } stmt_ty Continue(int lineno, int col_offset, PyArena *arena) { - stmt_ty p; - p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Continue_kind; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Continue_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty BoolOp(boolop_ty op, asdl_seq * values, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!op) { - PyErr_SetString(PyExc_ValueError, - "field op is required for BoolOp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = BoolOp_kind; - p->v.BoolOp.op = op; - p->v.BoolOp.values = values; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for BoolOp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = BoolOp_kind; + p->v.BoolOp.op = op; + p->v.BoolOp.values = values; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!left) { - PyErr_SetString(PyExc_ValueError, - "field left is required for BinOp"); - return NULL; - } - if (!op) { - PyErr_SetString(PyExc_ValueError, - "field op is required for BinOp"); - return NULL; - } - if (!right) { - PyErr_SetString(PyExc_ValueError, - "field right is required for BinOp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = BinOp_kind; - p->v.BinOp.left = left; - p->v.BinOp.op = op; - p->v.BinOp.right = right; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!left) { + PyErr_SetString(PyExc_ValueError, + "field left is required for BinOp"); + return NULL; + } + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for BinOp"); + return NULL; + } + if (!right) { + PyErr_SetString(PyExc_ValueError, + "field right is required for BinOp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = BinOp_kind; + p->v.BinOp.left = left; + p->v.BinOp.op = op; + p->v.BinOp.right = right; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!op) { - PyErr_SetString(PyExc_ValueError, - "field op is required for UnaryOp"); - return NULL; - } - if (!operand) { - PyErr_SetString(PyExc_ValueError, - "field operand is required for UnaryOp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = UnaryOp_kind; - p->v.UnaryOp.op = op; - p->v.UnaryOp.operand = operand; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for UnaryOp"); + return NULL; + } + if (!operand) { + PyErr_SetString(PyExc_ValueError, + "field operand is required for UnaryOp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = UnaryOp_kind; + p->v.UnaryOp.op = op; + p->v.UnaryOp.operand = operand; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!args) { - PyErr_SetString(PyExc_ValueError, - "field args is required for Lambda"); - return NULL; - } - if (!body) { - PyErr_SetString(PyExc_ValueError, - "field body is required for Lambda"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Lambda_kind; - p->v.Lambda.args = args; - p->v.Lambda.body = body; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!args) { + PyErr_SetString(PyExc_ValueError, + "field args is required for Lambda"); + return NULL; + } + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for Lambda"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Lambda_kind; + p->v.Lambda.args = args; + p->v.Lambda.body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!test) { - PyErr_SetString(PyExc_ValueError, - "field test is required for IfExp"); - return NULL; - } - if (!body) { - PyErr_SetString(PyExc_ValueError, - "field body is required for IfExp"); - return NULL; - } - if (!orelse) { - PyErr_SetString(PyExc_ValueError, - "field orelse is required for IfExp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = IfExp_kind; - p->v.IfExp.test = test; - p->v.IfExp.body = body; - p->v.IfExp.orelse = orelse; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for IfExp"); + return NULL; + } + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for IfExp"); + return NULL; + } + if (!orelse) { + PyErr_SetString(PyExc_ValueError, + "field orelse is required for IfExp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = IfExp_kind; + p->v.IfExp.test = test; + p->v.IfExp.body = body; + p->v.IfExp.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Dict(asdl_seq * keys, asdl_seq * values, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Dict_kind; - p->v.Dict.keys = keys; - p->v.Dict.values = values; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Dict_kind; + p->v.Dict.keys = keys; + p->v.Dict.values = values; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Set(asdl_seq * elts, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Set_kind; - p->v.Set.elts = elts; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Set_kind; + p->v.Set.elts = elts; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty ListComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!elt) { - PyErr_SetString(PyExc_ValueError, - "field elt is required for ListComp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ListComp_kind; - p->v.ListComp.elt = elt; - p->v.ListComp.generators = generators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!elt) { + PyErr_SetString(PyExc_ValueError, + "field elt is required for ListComp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ListComp_kind; + p->v.ListComp.elt = elt; + p->v.ListComp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty SetComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!elt) { - PyErr_SetString(PyExc_ValueError, - "field elt is required for SetComp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = SetComp_kind; - p->v.SetComp.elt = elt; - p->v.SetComp.generators = generators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!elt) { + PyErr_SetString(PyExc_ValueError, + "field elt is required for SetComp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = SetComp_kind; + p->v.SetComp.elt = elt; + p->v.SetComp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!key) { - PyErr_SetString(PyExc_ValueError, - "field key is required for DictComp"); - return NULL; - } - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for DictComp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = DictComp_kind; - p->v.DictComp.key = key; - p->v.DictComp.value = value; - p->v.DictComp.generators = generators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!key) { + PyErr_SetString(PyExc_ValueError, + "field key is required for DictComp"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for DictComp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = DictComp_kind; + p->v.DictComp.key = key; + p->v.DictComp.value = value; + p->v.DictComp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!elt) { - PyErr_SetString(PyExc_ValueError, - "field elt is required for GeneratorExp"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = GeneratorExp_kind; - p->v.GeneratorExp.elt = elt; - p->v.GeneratorExp.generators = generators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!elt) { + PyErr_SetString(PyExc_ValueError, + "field elt is required for GeneratorExp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = GeneratorExp_kind; + p->v.GeneratorExp.elt = elt; + p->v.GeneratorExp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Yield(expr_ty value, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Yield_kind; - p->v.Yield.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Yield_kind; + p->v.Yield.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty YieldFrom(expr_ty value, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for YieldFrom"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = YieldFrom_kind; - p->v.YieldFrom.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for YieldFrom"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = YieldFrom_kind; + p->v.YieldFrom.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!left) { - PyErr_SetString(PyExc_ValueError, - "field left is required for Compare"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Compare_kind; - p->v.Compare.left = left; - p->v.Compare.ops = ops; - p->v.Compare.comparators = comparators; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!left) { + PyErr_SetString(PyExc_ValueError, + "field left is required for Compare"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Compare_kind; + p->v.Compare.left = left; + p->v.Compare.ops = ops; + p->v.Compare.comparators = comparators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, expr_ty starargs, expr_ty kwargs, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!func) { - PyErr_SetString(PyExc_ValueError, - "field func is required for Call"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Call_kind; - p->v.Call.func = func; - p->v.Call.args = args; - p->v.Call.keywords = keywords; - p->v.Call.starargs = starargs; - p->v.Call.kwargs = kwargs; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!func) { + PyErr_SetString(PyExc_ValueError, + "field func is required for Call"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Call_kind; + p->v.Call.func = func; + p->v.Call.args = args; + p->v.Call.keywords = keywords; + p->v.Call.starargs = starargs; + p->v.Call.kwargs = kwargs; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Num(object n, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!n) { - PyErr_SetString(PyExc_ValueError, - "field n is required for Num"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Num_kind; - p->v.Num.n = n; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!n) { + PyErr_SetString(PyExc_ValueError, + "field n is required for Num"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Num_kind; + p->v.Num.n = n; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Str(string s, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!s) { - PyErr_SetString(PyExc_ValueError, - "field s is required for Str"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Str_kind; - p->v.Str.s = s; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!s) { + PyErr_SetString(PyExc_ValueError, + "field s is required for Str"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Str_kind; + p->v.Str.s = s; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Bytes(bytes s, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!s) { - PyErr_SetString(PyExc_ValueError, - "field s is required for Bytes"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Bytes_kind; - p->v.Bytes.s = s; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!s) { + PyErr_SetString(PyExc_ValueError, + "field s is required for Bytes"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Bytes_kind; + p->v.Bytes.s = s; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty NameConstant(singleton value, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for NameConstant"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = NameConstant_kind; - p->v.NameConstant.value = value; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for NameConstant"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = NameConstant_kind; + p->v.NameConstant.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Ellipsis(int lineno, int col_offset, PyArena *arena) { - expr_ty p; - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Ellipsis_kind; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Ellipsis_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Attribute"); - return NULL; - } - if (!attr) { - PyErr_SetString(PyExc_ValueError, - "field attr is required for Attribute"); - return NULL; - } - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Attribute"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Attribute_kind; - p->v.Attribute.value = value; - p->v.Attribute.attr = attr; - p->v.Attribute.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Attribute"); + return NULL; + } + if (!attr) { + PyErr_SetString(PyExc_ValueError, + "field attr is required for Attribute"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Attribute"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Attribute_kind; + p->v.Attribute.value = value; + p->v.Attribute.attr = attr; + p->v.Attribute.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Subscript"); - return NULL; - } - if (!slice) { - PyErr_SetString(PyExc_ValueError, - "field slice is required for Subscript"); - return NULL; - } - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Subscript"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Subscript_kind; - p->v.Subscript.value = value; - p->v.Subscript.slice = slice; - p->v.Subscript.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Subscript"); + return NULL; + } + if (!slice) { + PyErr_SetString(PyExc_ValueError, + "field slice is required for Subscript"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Subscript"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Subscript_kind; + p->v.Subscript.value = value; + p->v.Subscript.slice = slice; + p->v.Subscript.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Starred(expr_ty value, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Starred"); - return NULL; - } - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Starred"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Starred_kind; - p->v.Starred.value = value; - p->v.Starred.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Starred"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Starred"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Starred_kind; + p->v.Starred.value = value; + p->v.Starred.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Name(identifier id, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!id) { - PyErr_SetString(PyExc_ValueError, - "field id is required for Name"); - return NULL; - } - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Name"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Name_kind; - p->v.Name.id = id; - p->v.Name.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!id) { + PyErr_SetString(PyExc_ValueError, + "field id is required for Name"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Name"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Name_kind; + p->v.Name.id = id; + p->v.Name.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty List(asdl_seq * elts, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for List"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = List_kind; - p->v.List.elts = elts; - p->v.List.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for List"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = List_kind; + p->v.List.elts = elts; + p->v.List.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } expr_ty Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena) { - expr_ty p; - if (!ctx) { - PyErr_SetString(PyExc_ValueError, - "field ctx is required for Tuple"); - return NULL; - } - p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Tuple_kind; - p->v.Tuple.elts = elts; - p->v.Tuple.ctx = ctx; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + expr_ty p; + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Tuple"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Tuple_kind; + p->v.Tuple.elts = elts; + p->v.Tuple.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } slice_ty Slice(expr_ty lower, expr_ty upper, expr_ty step, PyArena *arena) { - slice_ty p; - p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Slice_kind; - p->v.Slice.lower = lower; - p->v.Slice.upper = upper; - p->v.Slice.step = step; - return p; + slice_ty p; + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Slice_kind; + p->v.Slice.lower = lower; + p->v.Slice.upper = upper; + p->v.Slice.step = step; + return p; } slice_ty ExtSlice(asdl_seq * dims, PyArena *arena) { - slice_ty p; - p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ExtSlice_kind; - p->v.ExtSlice.dims = dims; - return p; + slice_ty p; + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ExtSlice_kind; + p->v.ExtSlice.dims = dims; + return p; } slice_ty Index(expr_ty value, PyArena *arena) { - slice_ty p; - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for Index"); - return NULL; - } - p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = Index_kind; - p->v.Index.value = value; - return p; + slice_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Index"); + return NULL; + } + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = Index_kind; + p->v.Index.value = value; + return p; } comprehension_ty comprehension(expr_ty target, expr_ty iter, asdl_seq * ifs, PyArena *arena) { - comprehension_ty p; - if (!target) { - PyErr_SetString(PyExc_ValueError, - "field target is required for comprehension"); - return NULL; - } - if (!iter) { - PyErr_SetString(PyExc_ValueError, - "field iter is required for comprehension"); - return NULL; - } - p = (comprehension_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->target = target; - p->iter = iter; - p->ifs = ifs; - return p; + comprehension_ty p; + if (!target) { + PyErr_SetString(PyExc_ValueError, + "field target is required for comprehension"); + return NULL; + } + if (!iter) { + PyErr_SetString(PyExc_ValueError, + "field iter is required for comprehension"); + return NULL; + } + p = (comprehension_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->target = target; + p->iter = iter; + p->ifs = ifs; + return p; } excepthandler_ty ExceptHandler(expr_ty type, identifier name, asdl_seq * body, int lineno, int col_offset, PyArena *arena) { - excepthandler_ty p; - p = (excepthandler_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = ExceptHandler_kind; - p->v.ExceptHandler.type = type; - p->v.ExceptHandler.name = name; - p->v.ExceptHandler.body = body; - p->lineno = lineno; - p->col_offset = col_offset; - return p; + excepthandler_ty p; + p = (excepthandler_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ExceptHandler_kind; + p->v.ExceptHandler.type = type; + p->v.ExceptHandler.name = name; + p->v.ExceptHandler.body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; } arguments_ty arguments(asdl_seq * args, arg_ty vararg, asdl_seq * kwonlyargs, asdl_seq * kw_defaults, arg_ty kwarg, asdl_seq * defaults, PyArena *arena) { - arguments_ty p; - p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->args = args; - p->vararg = vararg; - p->kwonlyargs = kwonlyargs; - p->kw_defaults = kw_defaults; - p->kwarg = kwarg; - p->defaults = defaults; - return p; + arguments_ty p; + p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->args = args; + p->vararg = vararg; + p->kwonlyargs = kwonlyargs; + p->kw_defaults = kw_defaults; + p->kwarg = kwarg; + p->defaults = defaults; + return p; } arg_ty arg(identifier arg, expr_ty annotation, PyArena *arena) { - arg_ty p; - if (!arg) { - PyErr_SetString(PyExc_ValueError, - "field arg is required for arg"); - return NULL; - } - p = (arg_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->arg = arg; - p->annotation = annotation; - return p; + arg_ty p; + if (!arg) { + PyErr_SetString(PyExc_ValueError, + "field arg is required for arg"); + return NULL; + } + p = (arg_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->arg = arg; + p->annotation = annotation; + return p; } keyword_ty keyword(identifier arg, expr_ty value, PyArena *arena) { - keyword_ty p; - if (!arg) { - PyErr_SetString(PyExc_ValueError, - "field arg is required for keyword"); - return NULL; - } - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field value is required for keyword"); - return NULL; - } - p = (keyword_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->arg = arg; - p->value = value; - return p; + keyword_ty p; + if (!arg) { + PyErr_SetString(PyExc_ValueError, + "field arg is required for keyword"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for keyword"); + return NULL; + } + p = (keyword_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->arg = arg; + p->value = value; + return p; } alias_ty alias(identifier name, identifier asname, PyArena *arena) { - alias_ty p; - if (!name) { - PyErr_SetString(PyExc_ValueError, - "field name is required for alias"); - return NULL; - } - p = (alias_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->name = name; - p->asname = asname; - return p; + alias_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field name is required for alias"); + return NULL; + } + p = (alias_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->name = name; + p->asname = asname; + return p; } withitem_ty withitem(expr_ty context_expr, expr_ty optional_vars, PyArena *arena) { - withitem_ty p; - if (!context_expr) { - PyErr_SetString(PyExc_ValueError, - "field context_expr is required for withitem"); - return NULL; - } - p = (withitem_ty)PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->context_expr = context_expr; - p->optional_vars = optional_vars; - return p; + withitem_ty p; + if (!context_expr) { + PyErr_SetString(PyExc_ValueError, + "field context_expr is required for withitem"); + return NULL; + } + p = (withitem_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->context_expr = context_expr; + p->optional_vars = optional_vars; + return p; } PyObject* ast2obj_mod(void* _o) { - mod_ty o = (mod_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - switch (o->kind) { - case Module_kind: - result = PyType_GenericNew(Module_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Module.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Interactive_kind: - result = PyType_GenericNew(Interactive_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Interactive.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Expression_kind: - result = PyType_GenericNew(Expression_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Expression.body); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Suite_kind: - result = PyType_GenericNew(Suite_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Suite.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - } - return result; + mod_ty o = (mod_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case Module_kind: + result = PyType_GenericNew(Module_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Module.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Interactive_kind: + result = PyType_GenericNew(Interactive_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Interactive.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Expression_kind: + result = PyType_GenericNew(Expression_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Expression.body); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Suite_kind: + result = PyType_GenericNew(Suite_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Suite.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_stmt(void* _o) { - stmt_ty o = (stmt_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - switch (o->kind) { - case FunctionDef_kind: - result = PyType_GenericNew(FunctionDef_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_identifier(o->v.FunctionDef.name); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_arguments(o->v.FunctionDef.args); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.FunctionDef.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.FunctionDef.decorator_list, - ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_decorator_list, value) == - -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.FunctionDef.returns); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_returns, value) == -1) - goto failed; - Py_DECREF(value); - break; - case ClassDef_kind: - result = PyType_GenericNew(ClassDef_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_identifier(o->v.ClassDef.name); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ClassDef.bases, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_bases, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ClassDef.keywords, ast2obj_keyword); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.ClassDef.starargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.ClassDef.kwargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ClassDef.decorator_list, - ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_decorator_list, value) == - -1) - goto failed; - Py_DECREF(value); - break; - case Return_kind: - result = PyType_GenericNew(Return_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Return.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Delete_kind: - result = PyType_GenericNew(Delete_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Delete.targets, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_targets, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Assign_kind: - result = PyType_GenericNew(Assign_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Assign.targets, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_targets, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Assign.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case AugAssign_kind: - result = PyType_GenericNew(AugAssign_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.AugAssign.target); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_operator(o->v.AugAssign.op); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.AugAssign.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case For_kind: - result = PyType_GenericNew(For_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.For.target); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.For.iter); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_iter, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.For.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.For.orelse, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - break; - case While_kind: - result = PyType_GenericNew(While_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.While.test); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.While.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.While.orelse, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - break; - case If_kind: - result = PyType_GenericNew(If_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.If.test); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.If.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.If.orelse, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - break; - case With_kind: - result = PyType_GenericNew(With_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.With.items, ast2obj_withitem); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_items, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.With.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Raise_kind: - result = PyType_GenericNew(Raise_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Raise.exc); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_exc, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Raise.cause); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_cause, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Try_kind: - result = PyType_GenericNew(Try_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Try.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Try.handlers, ast2obj_excepthandler); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_handlers, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Try.orelse, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Try.finalbody, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_finalbody, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Assert_kind: - result = PyType_GenericNew(Assert_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Assert.test); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Assert.msg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_msg, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Import_kind: - result = PyType_GenericNew(Import_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Import.names, ast2obj_alias); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) - goto failed; - Py_DECREF(value); - break; - case ImportFrom_kind: - result = PyType_GenericNew(ImportFrom_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_identifier(o->v.ImportFrom.module); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_module, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ImportFrom.names, ast2obj_alias); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_int(o->v.ImportFrom.level); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_level, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Global_kind: - result = PyType_GenericNew(Global_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Global.names, ast2obj_identifier); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Nonlocal_kind: - result = PyType_GenericNew(Nonlocal_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Nonlocal.names, ast2obj_identifier); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Expr_kind: - result = PyType_GenericNew(Expr_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Expr.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Pass_kind: - result = PyType_GenericNew(Pass_type, NULL, NULL); - if (!result) goto failed; - break; - case Break_kind: - result = PyType_GenericNew(Break_type, NULL, NULL); - if (!result) goto failed; - break; - case Continue_kind: - result = PyType_GenericNew(Continue_type, NULL, NULL); - if (!result) goto failed; - break; - } - value = ast2obj_int(o->lineno); + stmt_ty o = (stmt_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case FunctionDef_kind: + result = PyType_GenericNew(FunctionDef_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.FunctionDef.name); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) + goto failed; Py_DECREF(value); - value = ast2obj_int(o->col_offset); + value = ast2obj_arguments(o->v.FunctionDef.args); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) + goto failed; Py_DECREF(value); - return result; + value = ast2obj_list(o->v.FunctionDef.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.FunctionDef.decorator_list, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_decorator_list, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.FunctionDef.returns); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_returns, value) == -1) + goto failed; + Py_DECREF(value); + break; + case ClassDef_kind: + result = PyType_GenericNew(ClassDef_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.ClassDef.name); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.bases, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_bases, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.keywords, ast2obj_keyword); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.ClassDef.starargs); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.ClassDef.kwargs); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.decorator_list, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_decorator_list, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Return_kind: + result = PyType_GenericNew(Return_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Return.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Delete_kind: + result = PyType_GenericNew(Delete_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Delete.targets, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_targets, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Assign_kind: + result = PyType_GenericNew(Assign_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Assign.targets, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_targets, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Assign.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case AugAssign_kind: + result = PyType_GenericNew(AugAssign_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.AugAssign.target); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_operator(o->v.AugAssign.op); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.AugAssign.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case For_kind: + result = PyType_GenericNew(For_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.For.target); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.For.iter); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_iter, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.For.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.For.orelse, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + break; + case While_kind: + result = PyType_GenericNew(While_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.While.test); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.While.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.While.orelse, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + break; + case If_kind: + result = PyType_GenericNew(If_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.If.test); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.If.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.If.orelse, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + break; + case With_kind: + result = PyType_GenericNew(With_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.With.items, ast2obj_withitem); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_items, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.With.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Raise_kind: + result = PyType_GenericNew(Raise_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Raise.exc); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_exc, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Raise.cause); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_cause, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Try_kind: + result = PyType_GenericNew(Try_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Try.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Try.handlers, ast2obj_excepthandler); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_handlers, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Try.orelse, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Try.finalbody, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_finalbody, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Assert_kind: + result = PyType_GenericNew(Assert_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Assert.test); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Assert.msg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_msg, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Import_kind: + result = PyType_GenericNew(Import_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Import.names, ast2obj_alias); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) + goto failed; + Py_DECREF(value); + break; + case ImportFrom_kind: + result = PyType_GenericNew(ImportFrom_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.ImportFrom.module); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_module, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ImportFrom.names, ast2obj_alias); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->v.ImportFrom.level); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_level, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Global_kind: + result = PyType_GenericNew(Global_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Global.names, ast2obj_identifier); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Nonlocal_kind: + result = PyType_GenericNew(Nonlocal_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Nonlocal.names, ast2obj_identifier); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_names, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Expr_kind: + result = PyType_GenericNew(Expr_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Expr.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Pass_kind: + result = PyType_GenericNew(Pass_type, NULL, NULL); + if (!result) goto failed; + break; + case Break_kind: + result = PyType_GenericNew(Break_type, NULL, NULL); + if (!result) goto failed; + break; + case Continue_kind: + result = PyType_GenericNew(Continue_type, NULL, NULL); + if (!result) goto failed; + break; + } + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_expr(void* _o) { - expr_ty o = (expr_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; + expr_ty o = (expr_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case BoolOp_kind: + result = PyType_GenericNew(BoolOp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_boolop(o->v.BoolOp.op); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.BoolOp.values, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_values, value) == -1) + goto failed; + Py_DECREF(value); + break; + case BinOp_kind: + result = PyType_GenericNew(BinOp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.BinOp.left); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_left, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_operator(o->v.BinOp.op); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.BinOp.right); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_right, value) == -1) + goto failed; + Py_DECREF(value); + break; + case UnaryOp_kind: + result = PyType_GenericNew(UnaryOp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_unaryop(o->v.UnaryOp.op); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.UnaryOp.operand); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_operand, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Lambda_kind: + result = PyType_GenericNew(Lambda_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_arguments(o->v.Lambda.args); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Lambda.body); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + case IfExp_kind: + result = PyType_GenericNew(IfExp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.IfExp.test); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.IfExp.body); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.IfExp.orelse); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Dict_kind: + result = PyType_GenericNew(Dict_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Dict.keys, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_keys, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Dict.values, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_values, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Set_kind: + result = PyType_GenericNew(Set_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Set.elts, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) + goto failed; + Py_DECREF(value); + break; + case ListComp_kind: + result = PyType_GenericNew(ListComp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.ListComp.elt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ListComp.generators, ast2obj_comprehension); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) + goto failed; + Py_DECREF(value); + break; + case SetComp_kind: + result = PyType_GenericNew(SetComp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.SetComp.elt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.SetComp.generators, ast2obj_comprehension); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) + goto failed; + Py_DECREF(value); + break; + case DictComp_kind: + result = PyType_GenericNew(DictComp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.DictComp.key); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_key, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.DictComp.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.DictComp.generators, ast2obj_comprehension); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) + goto failed; + Py_DECREF(value); + break; + case GeneratorExp_kind: + result = PyType_GenericNew(GeneratorExp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.GeneratorExp.elt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.GeneratorExp.generators, + ast2obj_comprehension); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Yield_kind: + result = PyType_GenericNew(Yield_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Yield.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case YieldFrom_kind: + result = PyType_GenericNew(YieldFrom_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.YieldFrom.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Compare_kind: + result = PyType_GenericNew(Compare_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Compare.left); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_left, value) == -1) + goto failed; + Py_DECREF(value); + { + Py_ssize_t i, n = asdl_seq_LEN(o->v.Compare.ops); + value = PyList_New(n); + if (!value) goto failed; + for(i = 0; i < n; i++) + PyList_SET_ITEM(value, i, ast2obj_cmpop((cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i))); } - - switch (o->kind) { - case BoolOp_kind: - result = PyType_GenericNew(BoolOp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_boolop(o->v.BoolOp.op); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.BoolOp.values, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_values, value) == -1) - goto failed; - Py_DECREF(value); - break; - case BinOp_kind: - result = PyType_GenericNew(BinOp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.BinOp.left); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_left, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_operator(o->v.BinOp.op); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.BinOp.right); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_right, value) == -1) - goto failed; - Py_DECREF(value); - break; - case UnaryOp_kind: - result = PyType_GenericNew(UnaryOp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_unaryop(o->v.UnaryOp.op); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_op, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.UnaryOp.operand); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_operand, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Lambda_kind: - result = PyType_GenericNew(Lambda_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_arguments(o->v.Lambda.args); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Lambda.body); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - case IfExp_kind: - result = PyType_GenericNew(IfExp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.IfExp.test); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_test, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.IfExp.body); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.IfExp.orelse); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Dict_kind: - result = PyType_GenericNew(Dict_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Dict.keys, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_keys, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Dict.values, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_values, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Set_kind: - result = PyType_GenericNew(Set_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Set.elts, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) - goto failed; - Py_DECREF(value); - break; - case ListComp_kind: - result = PyType_GenericNew(ListComp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.ListComp.elt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ListComp.generators, - ast2obj_comprehension); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case SetComp_kind: - result = PyType_GenericNew(SetComp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.SetComp.elt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.SetComp.generators, - ast2obj_comprehension); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case DictComp_kind: - result = PyType_GenericNew(DictComp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.DictComp.key); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_key, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.DictComp.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.DictComp.generators, - ast2obj_comprehension); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case GeneratorExp_kind: - result = PyType_GenericNew(GeneratorExp_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.GeneratorExp.elt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elt, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.GeneratorExp.generators, - ast2obj_comprehension); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_generators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Yield_kind: - result = PyType_GenericNew(Yield_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Yield.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case YieldFrom_kind: - result = PyType_GenericNew(YieldFrom_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.YieldFrom.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Compare_kind: - result = PyType_GenericNew(Compare_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Compare.left); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_left, value) == -1) - goto failed; - Py_DECREF(value); - { - Py_ssize_t i, n = asdl_seq_LEN(o->v.Compare.ops); - value = PyList_New(n); - if (!value) goto failed; - for(i = 0; i < n; i++) - PyList_SET_ITEM(value, i, ast2obj_cmpop((cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i))); - } - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ops, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Compare.comparators, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_comparators, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Call_kind: - result = PyType_GenericNew(Call_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Call.func); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_func, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Call.args, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.Call.keywords, ast2obj_keyword); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Call.starargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Call.kwargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Num_kind: - result = PyType_GenericNew(Num_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_object(o->v.Num.n); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_n, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Str_kind: - result = PyType_GenericNew(Str_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_string(o->v.Str.s); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_s, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Bytes_kind: - result = PyType_GenericNew(Bytes_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_bytes(o->v.Bytes.s); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_s, value) == -1) - goto failed; - Py_DECREF(value); - break; - case NameConstant_kind: - result = PyType_GenericNew(NameConstant_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_singleton(o->v.NameConstant.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Ellipsis_kind: - result = PyType_GenericNew(Ellipsis_type, NULL, NULL); - if (!result) goto failed; - break; - case Attribute_kind: - result = PyType_GenericNew(Attribute_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Attribute.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_identifier(o->v.Attribute.attr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_attr, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Attribute.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Subscript_kind: - result = PyType_GenericNew(Subscript_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Subscript.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_slice(o->v.Subscript.slice); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_slice, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Subscript.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Starred_kind: - result = PyType_GenericNew(Starred_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Starred.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Starred.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Name_kind: - result = PyType_GenericNew(Name_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_identifier(o->v.Name.id); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_id, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Name.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case List_kind: - result = PyType_GenericNew(List_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.List.elts, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.List.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Tuple_kind: - result = PyType_GenericNew(Tuple_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.Tuple.elts, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr_context(o->v.Tuple.ctx); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) - goto failed; - Py_DECREF(value); - break; - } - value = ast2obj_int(o->lineno); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_ops, value) == -1) + goto failed; Py_DECREF(value); - value = ast2obj_int(o->col_offset); + value = ast2obj_list(o->v.Compare.comparators, ast2obj_expr); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_comparators, value) == -1) + goto failed; Py_DECREF(value); - return result; + break; + case Call_kind: + result = PyType_GenericNew(Call_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Call.func); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_func, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Call.args, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Call.keywords, ast2obj_keyword); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Call.starargs); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Call.kwargs); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Num_kind: + result = PyType_GenericNew(Num_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_object(o->v.Num.n); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_n, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Str_kind: + result = PyType_GenericNew(Str_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_string(o->v.Str.s); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_s, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Bytes_kind: + result = PyType_GenericNew(Bytes_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_bytes(o->v.Bytes.s); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_s, value) == -1) + goto failed; + Py_DECREF(value); + break; + case NameConstant_kind: + result = PyType_GenericNew(NameConstant_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_singleton(o->v.NameConstant.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Ellipsis_kind: + result = PyType_GenericNew(Ellipsis_type, NULL, NULL); + if (!result) goto failed; + break; + case Attribute_kind: + result = PyType_GenericNew(Attribute_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Attribute.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->v.Attribute.attr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_attr, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Attribute.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Subscript_kind: + result = PyType_GenericNew(Subscript_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Subscript.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_slice(o->v.Subscript.slice); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_slice, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Subscript.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Starred_kind: + result = PyType_GenericNew(Starred_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Starred.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Starred.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Name_kind: + result = PyType_GenericNew(Name_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.Name.id); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_id, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Name.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case List_kind: + result = PyType_GenericNew(List_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.List.elts, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.List.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Tuple_kind: + result = PyType_GenericNew(Tuple_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Tuple.elts, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_elts, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Tuple.ctx); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ctx, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_expr_context(expr_context_ty o) { - switch(o) { - case Load: - Py_INCREF(Load_singleton); - return Load_singleton; - case Store: - Py_INCREF(Store_singleton); - return Store_singleton; - case Del: - Py_INCREF(Del_singleton); - return Del_singleton; - case AugLoad: - Py_INCREF(AugLoad_singleton); - return AugLoad_singleton; - case AugStore: - Py_INCREF(AugStore_singleton); - return AugStore_singleton; - case Param: - Py_INCREF(Param_singleton); - return Param_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown expr_context found"); - return NULL; - } + switch(o) { + case Load: + Py_INCREF(Load_singleton); + return Load_singleton; + case Store: + Py_INCREF(Store_singleton); + return Store_singleton; + case Del: + Py_INCREF(Del_singleton); + return Del_singleton; + case AugLoad: + Py_INCREF(AugLoad_singleton); + return AugLoad_singleton; + case AugStore: + Py_INCREF(AugStore_singleton); + return AugStore_singleton; + case Param: + Py_INCREF(Param_singleton); + return Param_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown expr_context found"); + return NULL; + } } PyObject* ast2obj_slice(void* _o) { - slice_ty o = (slice_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - switch (o->kind) { - case Slice_kind: - result = PyType_GenericNew(Slice_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Slice.lower); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_lower, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Slice.upper); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_upper, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Slice.step); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_step, value) == -1) - goto failed; - Py_DECREF(value); - break; - case ExtSlice_kind: - result = PyType_GenericNew(ExtSlice_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(o->v.ExtSlice.dims, ast2obj_slice); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_dims, value) == -1) - goto failed; - Py_DECREF(value); - break; - case Index_kind: - result = PyType_GenericNew(Index_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.Index.value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - break; - } - return result; + slice_ty o = (slice_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case Slice_kind: + result = PyType_GenericNew(Slice_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Slice.lower); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_lower, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Slice.upper); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_upper, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Slice.step); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_step, value) == -1) + goto failed; + Py_DECREF(value); + break; + case ExtSlice_kind: + result = PyType_GenericNew(ExtSlice_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.ExtSlice.dims, ast2obj_slice); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_dims, value) == -1) + goto failed; + Py_DECREF(value); + break; + case Index_kind: + result = PyType_GenericNew(Index_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Index.value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_boolop(boolop_ty o) { - switch(o) { - case And: - Py_INCREF(And_singleton); - return And_singleton; - case Or: - Py_INCREF(Or_singleton); - return Or_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown boolop found"); - return NULL; - } + switch(o) { + case And: + Py_INCREF(And_singleton); + return And_singleton; + case Or: + Py_INCREF(Or_singleton); + return Or_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown boolop found"); + return NULL; + } } PyObject* ast2obj_operator(operator_ty o) { - switch(o) { - case Add: - Py_INCREF(Add_singleton); - return Add_singleton; - case Sub: - Py_INCREF(Sub_singleton); - return Sub_singleton; - case Mult: - Py_INCREF(Mult_singleton); - return Mult_singleton; - case Div: - Py_INCREF(Div_singleton); - return Div_singleton; - case Mod: - Py_INCREF(Mod_singleton); - return Mod_singleton; - case Pow: - Py_INCREF(Pow_singleton); - return Pow_singleton; - case LShift: - Py_INCREF(LShift_singleton); - return LShift_singleton; - case RShift: - Py_INCREF(RShift_singleton); - return RShift_singleton; - case BitOr: - Py_INCREF(BitOr_singleton); - return BitOr_singleton; - case BitXor: - Py_INCREF(BitXor_singleton); - return BitXor_singleton; - case BitAnd: - Py_INCREF(BitAnd_singleton); - return BitAnd_singleton; - case FloorDiv: - Py_INCREF(FloorDiv_singleton); - return FloorDiv_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown operator found"); - return NULL; - } + switch(o) { + case Add: + Py_INCREF(Add_singleton); + return Add_singleton; + case Sub: + Py_INCREF(Sub_singleton); + return Sub_singleton; + case Mult: + Py_INCREF(Mult_singleton); + return Mult_singleton; + case Div: + Py_INCREF(Div_singleton); + return Div_singleton; + case Mod: + Py_INCREF(Mod_singleton); + return Mod_singleton; + case Pow: + Py_INCREF(Pow_singleton); + return Pow_singleton; + case LShift: + Py_INCREF(LShift_singleton); + return LShift_singleton; + case RShift: + Py_INCREF(RShift_singleton); + return RShift_singleton; + case BitOr: + Py_INCREF(BitOr_singleton); + return BitOr_singleton; + case BitXor: + Py_INCREF(BitXor_singleton); + return BitXor_singleton; + case BitAnd: + Py_INCREF(BitAnd_singleton); + return BitAnd_singleton; + case FloorDiv: + Py_INCREF(FloorDiv_singleton); + return FloorDiv_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown operator found"); + return NULL; + } } PyObject* ast2obj_unaryop(unaryop_ty o) { - switch(o) { - case Invert: - Py_INCREF(Invert_singleton); - return Invert_singleton; - case Not: - Py_INCREF(Not_singleton); - return Not_singleton; - case UAdd: - Py_INCREF(UAdd_singleton); - return UAdd_singleton; - case USub: - Py_INCREF(USub_singleton); - return USub_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown unaryop found"); - return NULL; - } + switch(o) { + case Invert: + Py_INCREF(Invert_singleton); + return Invert_singleton; + case Not: + Py_INCREF(Not_singleton); + return Not_singleton; + case UAdd: + Py_INCREF(UAdd_singleton); + return UAdd_singleton; + case USub: + Py_INCREF(USub_singleton); + return USub_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown unaryop found"); + return NULL; + } } PyObject* ast2obj_cmpop(cmpop_ty o) { - switch(o) { - case Eq: - Py_INCREF(Eq_singleton); - return Eq_singleton; - case NotEq: - Py_INCREF(NotEq_singleton); - return NotEq_singleton; - case Lt: - Py_INCREF(Lt_singleton); - return Lt_singleton; - case LtE: - Py_INCREF(LtE_singleton); - return LtE_singleton; - case Gt: - Py_INCREF(Gt_singleton); - return Gt_singleton; - case GtE: - Py_INCREF(GtE_singleton); - return GtE_singleton; - case Is: - Py_INCREF(Is_singleton); - return Is_singleton; - case IsNot: - Py_INCREF(IsNot_singleton); - return IsNot_singleton; - case In: - Py_INCREF(In_singleton); - return In_singleton; - case NotIn: - Py_INCREF(NotIn_singleton); - return NotIn_singleton; - default: - /* should never happen, but just in case ... */ - PyErr_Format(PyExc_SystemError, "unknown cmpop found"); - return NULL; - } + switch(o) { + case Eq: + Py_INCREF(Eq_singleton); + return Eq_singleton; + case NotEq: + Py_INCREF(NotEq_singleton); + return NotEq_singleton; + case Lt: + Py_INCREF(Lt_singleton); + return Lt_singleton; + case LtE: + Py_INCREF(LtE_singleton); + return LtE_singleton; + case Gt: + Py_INCREF(Gt_singleton); + return Gt_singleton; + case GtE: + Py_INCREF(GtE_singleton); + return GtE_singleton; + case Is: + Py_INCREF(Is_singleton); + return Is_singleton; + case IsNot: + Py_INCREF(IsNot_singleton); + return IsNot_singleton; + case In: + Py_INCREF(In_singleton); + return In_singleton; + case NotIn: + Py_INCREF(NotIn_singleton); + return NotIn_singleton; + default: + /* should never happen, but just in case ... */ + PyErr_Format(PyExc_SystemError, "unknown cmpop found"); + return NULL; + } } PyObject* ast2obj_comprehension(void* _o) { - comprehension_ty o = (comprehension_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(comprehension_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_expr(o->target); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->iter); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_iter, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->ifs, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_ifs, value) == -1) - goto failed; - Py_DECREF(value); - return result; + comprehension_ty o = (comprehension_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(comprehension_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_expr(o->target); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_target, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->iter); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_iter, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->ifs, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_ifs, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_excepthandler(void* _o) { - excepthandler_ty o = (excepthandler_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - switch (o->kind) { - case ExceptHandler_kind: - result = PyType_GenericNew(ExceptHandler_type, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(o->v.ExceptHandler.type); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_type, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_identifier(o->v.ExceptHandler.name); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->v.ExceptHandler.body, ast2obj_stmt); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) - goto failed; - Py_DECREF(value); - break; - } - value = ast2obj_int(o->lineno); + excepthandler_ty o = (excepthandler_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case ExceptHandler_kind: + result = PyType_GenericNew(ExceptHandler_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.ExceptHandler.type); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_type, value) == -1) + goto failed; Py_DECREF(value); - value = ast2obj_int(o->col_offset); + value = ast2obj_identifier(o->v.ExceptHandler.name); if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) - goto failed; + if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) + goto failed; Py_DECREF(value); - return result; + value = ast2obj_list(o->v.ExceptHandler.body, ast2obj_stmt); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_arguments(void* _o) { - arguments_ty o = (arguments_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(arguments_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_list(o->args, ast2obj_arg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_arg(o->vararg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_vararg, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->kwonlyargs, ast2obj_arg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwonlyargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->kw_defaults, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kw_defaults, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_arg(o->kwarg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwarg, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_list(o->defaults, ast2obj_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_defaults, value) == -1) - goto failed; - Py_DECREF(value); - return result; + arguments_ty o = (arguments_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(arguments_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_list(o->args, ast2obj_arg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_args, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_arg(o->vararg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_vararg, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->kwonlyargs, ast2obj_arg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kwonlyargs, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->kw_defaults, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kw_defaults, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_arg(o->kwarg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_kwarg, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->defaults, ast2obj_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_defaults, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_arg(void* _o) { - arg_ty o = (arg_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(arg_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_identifier(o->arg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_arg, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->annotation); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_annotation, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_int(o->lineno); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) - goto failed; - Py_DECREF(value); - value = ast2obj_int(o->col_offset); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) - goto failed; - Py_DECREF(value); - return result; + arg_ty o = (arg_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(arg_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_identifier(o->arg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_arg, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->annotation); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_annotation, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_col_offset, value) < 0) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_keyword(void* _o) { - keyword_ty o = (keyword_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(keyword_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_identifier(o->arg); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_arg, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->value); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) - goto failed; - Py_DECREF(value); - return result; + keyword_ty o = (keyword_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(keyword_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_identifier(o->arg); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_arg, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->value); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_value, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_alias(void* _o) { - alias_ty o = (alias_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(alias_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_identifier(o->name); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_identifier(o->asname); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_asname, value) == -1) - goto failed; - Py_DECREF(value); - return result; + alias_ty o = (alias_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(alias_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_identifier(o->name); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_name, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->asname); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_asname, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } PyObject* ast2obj_withitem(void* _o) { - withitem_ty o = (withitem_ty)_o; - PyObject *result = NULL, *value = NULL; - if (!o) { - Py_INCREF(Py_None); - return Py_None; - } - - result = PyType_GenericNew(withitem_type, NULL, NULL); - if (!result) return NULL; - value = ast2obj_expr(o->context_expr); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_context_expr, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->optional_vars); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_optional_vars, value) == -1) - goto failed; - Py_DECREF(value); - return result; + withitem_ty o = (withitem_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(withitem_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_expr(o->context_expr); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_context_expr, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->optional_vars); + if (!value) goto failed; + if (_PyObject_SetAttrId(result, &PyId_optional_vars, value) == -1) + goto failed; + Py_DECREF(value); + return result; failed: - Py_XDECREF(value); - Py_XDECREF(result); - return NULL; + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; } int obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Module_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* body; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Module field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Module_type); - if (isinstance == -1) { - return 1; + *out = Module(body, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Interactive_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* body; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Interactive field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive"); + return 1; } - if (isinstance) { - asdl_seq* body; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Module field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module"); - return 1; - } - *out = Module(body, arena); - if (*out == NULL) goto failed; - return 0; + *out = Interactive(body, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Expression_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty body; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &body, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Interactive_type); - if (isinstance == -1) { - return 1; + *out = Expression(body, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Suite_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* body; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Suite field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Suite"); + return 1; } - if (isinstance) { - asdl_seq* body; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Interactive field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive"); - return 1; - } - *out = Interactive(body, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Expression_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty body; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &body, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression"); - return 1; - } - *out = Expression(body, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Suite_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - asdl_seq* body; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Suite field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Suite"); - return 1; - } - *out = Suite(body, arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of mod, but got %R", obj); - failed: - Py_XDECREF(tmp); - return 1; + *out = Suite(body, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of mod, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - int lineno; - int col_offset; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + int lineno; + int col_offset; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + if (_PyObject_HasAttrId(obj, &PyId_lineno)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_lineno); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &lineno, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &col_offset, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt"); + return 1; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)FunctionDef_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier name; + arguments_ty args; + asdl_seq* body; + asdl_seq* decorator_list; + expr_ty returns; + + if (_PyObject_HasAttrId(obj, &PyId_name)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_name); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &name, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_lineno)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_lineno); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &lineno, arena); + if (_PyObject_HasAttrId(obj, &PyId_args)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_args); + if (tmp == NULL) goto failed; + res = obj2ast_arguments(tmp, &args, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "FunctionDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &col_offset, arena); + if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "FunctionDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + decorator_list = asdl_seq_new(len, arena); + if (decorator_list == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(decorator_list, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)FunctionDef_type); - if (isinstance == -1) { - return 1; + if (exists_not_none(obj, &PyId_returns)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_returns); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &returns, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + returns = NULL; } - if (isinstance) { - identifier name; - arguments_ty args; - asdl_seq* body; - asdl_seq* decorator_list; - expr_ty returns; - - if (_PyObject_HasAttrId(obj, &PyId_name)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_name); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &name, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_args)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_args); - if (tmp == NULL) goto failed; - res = obj2ast_arguments(tmp, &args, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "FunctionDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "FunctionDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - decorator_list = asdl_seq_new(len, arena); - if (decorator_list == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(decorator_list, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef"); - return 1; - } - if (exists_not_none(obj, &PyId_returns)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_returns); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &returns, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - returns = NULL; - } - *out = FunctionDef(name, args, body, decorator_list, returns, - lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = FunctionDef(name, args, body, decorator_list, returns, lineno, + col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ClassDef_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier name; + asdl_seq* bases; + asdl_seq* keywords; + expr_ty starargs; + expr_ty kwargs; + asdl_seq* body; + asdl_seq* decorator_list; + + if (_PyObject_HasAttrId(obj, &PyId_name)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_name); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &name, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)ClassDef_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_bases)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_bases); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"bases\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + bases = asdl_seq_new(len, arena); + if (bases == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(bases, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef"); + return 1; } - if (isinstance) { - identifier name; - asdl_seq* bases; - asdl_seq* keywords; - expr_ty starargs; - expr_ty kwargs; - asdl_seq* body; - asdl_seq* decorator_list; - - if (_PyObject_HasAttrId(obj, &PyId_name)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_name); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &name, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_bases)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_bases); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"bases\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - bases = asdl_seq_new(len, arena); - if (bases == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(bases, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_keywords)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_keywords); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - keywords = asdl_seq_new(len, arena); - if (keywords == NULL) goto failed; - for (i = 0; i < len; i++) { - keyword_ty value; - res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(keywords, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); - return 1; - } - if (exists_not_none(obj, &PyId_starargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_starargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &starargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - starargs = NULL; - } - if (exists_not_none(obj, &PyId_kwargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &kwargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - kwargs = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - decorator_list = asdl_seq_new(len, arena); - if (decorator_list == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(decorator_list, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef"); - return 1; - } - *out = ClassDef(name, bases, keywords, starargs, kwargs, body, - decorator_list, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_keywords)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_keywords); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + keywords = asdl_seq_new(len, arena); + if (keywords == NULL) goto failed; + for (i = 0; i < len; i++) { + keyword_ty value; + res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(keywords, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Return_type); - if (isinstance == -1) { - return 1; + if (exists_not_none(obj, &PyId_starargs)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_starargs); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &starargs, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + starargs = NULL; } - if (isinstance) { + if (exists_not_none(obj, &PyId_kwargs)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &kwargs, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + kwargs = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + decorator_list = asdl_seq_new(len, arena); + if (decorator_list == NULL) goto failed; + for (i = 0; i < len; i++) { expr_ty value; - - if (exists_not_none(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - value = NULL; - } - *out = Return(value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(decorator_list, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Delete_type); - if (isinstance == -1) { - return 1; + *out = ClassDef(name, bases, keywords, starargs, kwargs, body, + decorator_list, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Return_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (exists_not_none(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + value = NULL; } - if (isinstance) { - asdl_seq* targets; - - if (_PyObject_HasAttrId(obj, &PyId_targets)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_targets); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Delete field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - targets = asdl_seq_new(len, arena); - if (targets == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(targets, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete"); - return 1; - } - *out = Delete(targets, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Return(value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Delete_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* targets; + + if (_PyObject_HasAttrId(obj, &PyId_targets)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_targets); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Delete field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + targets = asdl_seq_new(len, arena); + if (targets == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(targets, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Assign_type); - if (isinstance == -1) { - return 1; + *out = Delete(targets, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Assign_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* targets; + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_targets)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_targets); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Assign field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + targets = asdl_seq_new(len, arena); + if (targets == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(targets, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign"); + return 1; } - if (isinstance) { - asdl_seq* targets; - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_targets)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_targets); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Assign field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - targets = asdl_seq_new(len, arena); - if (targets == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(targets, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign"); - return 1; - } - *out = Assign(targets, value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)AugAssign_type); - if (isinstance == -1) { - return 1; + *out = Assign(targets, value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)AugAssign_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty target; + operator_ty op; + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_target)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_target); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &target, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign"); + return 1; } - if (isinstance) { - expr_ty target; - operator_ty op; - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_target)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_target); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &target, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_op)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_op); - if (tmp == NULL) goto failed; - res = obj2ast_operator(tmp, &op, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign"); - return 1; - } - *out = AugAssign(target, op, value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_op)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_op); + if (tmp == NULL) goto failed; + res = obj2ast_operator(tmp, &op, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)For_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign"); + return 1; } - if (isinstance) { - expr_ty target; - expr_ty iter; - asdl_seq* body; - asdl_seq* orelse; - - if (_PyObject_HasAttrId(obj, &PyId_target)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_target); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &target, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_iter)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_iter); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &iter, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "For field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "For field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - orelse = asdl_seq_new(len, arena); - if (orelse == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(orelse, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For"); - return 1; - } - *out = For(target, iter, body, orelse, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; + *out = AugAssign(target, op, value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)For_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty target; + expr_ty iter; + asdl_seq* body; + asdl_seq* orelse; + + if (_PyObject_HasAttrId(obj, &PyId_target)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_target); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &target, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)While_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_iter)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_iter); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &iter, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For"); + return 1; } - if (isinstance) { - expr_ty test; - asdl_seq* body; - asdl_seq* orelse; - - if (_PyObject_HasAttrId(obj, &PyId_test)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_test); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &test, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "While field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "While field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - orelse = asdl_seq_new(len, arena); - if (orelse == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(orelse, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While"); - return 1; - } - *out = While(test, body, orelse, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "For field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)If_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "For field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + orelse = asdl_seq_new(len, arena); + if (orelse == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(orelse, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For"); + return 1; } - if (isinstance) { - expr_ty test; - asdl_seq* body; - asdl_seq* orelse; - - if (_PyObject_HasAttrId(obj, &PyId_test)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_test); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &test, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "If field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "If field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - orelse = asdl_seq_new(len, arena); - if (orelse == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(orelse, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If"); - return 1; - } - *out = If(test, body, orelse, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = For(target, iter, body, orelse, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)While_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty test; + asdl_seq* body; + asdl_seq* orelse; + + if (_PyObject_HasAttrId(obj, &PyId_test)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_test); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &test, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)With_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "While field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While"); + return 1; } - if (isinstance) { - asdl_seq* items; - asdl_seq* body; - - if (_PyObject_HasAttrId(obj, &PyId_items)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_items); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "With field \"items\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - items = asdl_seq_new(len, arena); - if (items == NULL) goto failed; - for (i = 0; i < len; i++) { - withitem_ty value; - res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(items, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "With field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With"); - return 1; - } - *out = With(items, body, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "While field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + orelse = asdl_seq_new(len, arena); + if (orelse == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(orelse, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Raise_type); - if (isinstance == -1) { - return 1; + *out = While(test, body, orelse, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)If_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty test; + asdl_seq* body; + asdl_seq* orelse; + + if (_PyObject_HasAttrId(obj, &PyId_test)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_test); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &test, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If"); + return 1; } - if (isinstance) { - expr_ty exc; - expr_ty cause; - - if (exists_not_none(obj, &PyId_exc)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_exc); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &exc, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - exc = NULL; - } - if (exists_not_none(obj, &PyId_cause)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_cause); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &cause, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - cause = NULL; - } - *out = Raise(exc, cause, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "If field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Try_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "If field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + orelse = asdl_seq_new(len, arena); + if (orelse == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(orelse, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If"); + return 1; } - if (isinstance) { - asdl_seq* body; - asdl_seq* handlers; - asdl_seq* orelse; - asdl_seq* finalbody; - - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Try field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_handlers)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_handlers); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Try field \"handlers\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - handlers = asdl_seq_new(len, arena); - if (handlers == NULL) goto failed; - for (i = 0; i < len; i++) { - excepthandler_ty value; - res = obj2ast_excepthandler(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(handlers, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Try field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - orelse = asdl_seq_new(len, arena); - if (orelse == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(orelse, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_finalbody)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_finalbody); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Try field \"finalbody\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - finalbody = asdl_seq_new(len, arena); - if (finalbody == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(finalbody, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try"); - return 1; - } - *out = Try(body, handlers, orelse, finalbody, lineno, - col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = If(test, body, orelse, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)With_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* items; + asdl_seq* body; + + if (_PyObject_HasAttrId(obj, &PyId_items)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_items); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "With field \"items\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + items = asdl_seq_new(len, arena); + if (items == NULL) goto failed; + for (i = 0; i < len; i++) { + withitem_ty value; + res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(items, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Assert_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "With field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With"); + return 1; } - if (isinstance) { - expr_ty test; - expr_ty msg; - - if (_PyObject_HasAttrId(obj, &PyId_test)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_test); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &test, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert"); - return 1; - } - if (exists_not_none(obj, &PyId_msg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_msg); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &msg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - msg = NULL; - } - *out = Assert(test, msg, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = With(items, body, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Raise_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty exc; + expr_ty cause; + + if (exists_not_none(obj, &PyId_exc)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_exc); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &exc, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + exc = NULL; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Import_type); - if (isinstance == -1) { - return 1; + if (exists_not_none(obj, &PyId_cause)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_cause); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &cause, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + cause = NULL; } - if (isinstance) { - asdl_seq* names; - - if (_PyObject_HasAttrId(obj, &PyId_names)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_names); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Import field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - names = asdl_seq_new(len, arena); - if (names == NULL) goto failed; - for (i = 0; i < len; i++) { - alias_ty value; - res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(names, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import"); - return 1; - } - *out = Import(names, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Raise(exc, cause, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Try_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* body; + asdl_seq* handlers; + asdl_seq* orelse; + asdl_seq* finalbody; + + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Try field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)ImportFrom_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_handlers)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_handlers); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Try field \"handlers\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + handlers = asdl_seq_new(len, arena); + if (handlers == NULL) goto failed; + for (i = 0; i < len; i++) { + excepthandler_ty value; + res = obj2ast_excepthandler(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(handlers, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try"); + return 1; } - if (isinstance) { - identifier module; - asdl_seq* names; - int level; - - if (exists_not_none(obj, &PyId_module)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_module); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &module, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - module = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_names)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_names); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ImportFrom field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - names = asdl_seq_new(len, arena); - if (names == NULL) goto failed; - for (i = 0; i < len; i++) { - alias_ty value; - res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(names, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom"); - return 1; - } - if (exists_not_none(obj, &PyId_level)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_level); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &level, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - level = 0; - } - *out = ImportFrom(module, names, level, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Try field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + orelse = asdl_seq_new(len, arena); + if (orelse == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(orelse, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Global_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_finalbody)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_finalbody); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Try field \"finalbody\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + finalbody = asdl_seq_new(len, arena); + if (finalbody == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(finalbody, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try"); + return 1; } - if (isinstance) { - asdl_seq* names; - - if (_PyObject_HasAttrId(obj, &PyId_names)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_names); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Global field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - names = asdl_seq_new(len, arena); - if (names == NULL) goto failed; - for (i = 0; i < len; i++) { - identifier value; - res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(names, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global"); - return 1; - } - *out = Global(names, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Try(body, handlers, orelse, finalbody, lineno, col_offset, + arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Assert_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty test; + expr_ty msg; + + if (_PyObject_HasAttrId(obj, &PyId_test)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_test); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &test, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Nonlocal_type); - if (isinstance == -1) { - return 1; + if (exists_not_none(obj, &PyId_msg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_msg); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &msg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + msg = NULL; } - if (isinstance) { - asdl_seq* names; - - if (_PyObject_HasAttrId(obj, &PyId_names)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_names); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Nonlocal field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - names = asdl_seq_new(len, arena); - if (names == NULL) goto failed; - for (i = 0; i < len; i++) { - identifier value; - res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(names, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal"); - return 1; - } - *out = Nonlocal(names, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Assert(test, msg, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Import_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* names; + + if (_PyObject_HasAttrId(obj, &PyId_names)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_names); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Import field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + names = asdl_seq_new(len, arena); + if (names == NULL) goto failed; + for (i = 0; i < len; i++) { + alias_ty value; + res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(names, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Expr_type); - if (isinstance == -1) { - return 1; + *out = Import(names, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ImportFrom_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier module; + asdl_seq* names; + int level; + + if (exists_not_none(obj, &PyId_module)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_module); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &module, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + module = NULL; } - if (isinstance) { - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr"); - return 1; - } - *out = Expr(value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_names)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_names); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ImportFrom field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + names = asdl_seq_new(len, arena); + if (names == NULL) goto failed; + for (i = 0; i < len; i++) { + alias_ty value; + res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(names, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Pass_type); - if (isinstance == -1) { - return 1; + if (exists_not_none(obj, &PyId_level)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_level); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &level, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + level = 0; } - if (isinstance) { - - *out = Pass(lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = ImportFrom(module, names, level, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Global_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* names; + + if (_PyObject_HasAttrId(obj, &PyId_names)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_names); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Global field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + names = asdl_seq_new(len, arena); + if (names == NULL) goto failed; + for (i = 0; i < len; i++) { + identifier value; + res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(names, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Break_type); - if (isinstance == -1) { - return 1; + *out = Global(names, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Nonlocal_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* names; + + if (_PyObject_HasAttrId(obj, &PyId_names)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_names); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Nonlocal field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + names = asdl_seq_new(len, arena); + if (names == NULL) goto failed; + for (i = 0; i < len; i++) { + identifier value; + res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(names, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal"); + return 1; } - if (isinstance) { - - *out = Break(lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Nonlocal(names, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Expr_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Continue_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - - *out = Continue(lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of stmt, but got %R", obj); - failed: - Py_XDECREF(tmp); + *out = Expr(value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Pass_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + + *out = Pass(lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Break_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + + *out = Break(lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Continue_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + + *out = Continue(lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of stmt, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - int lineno; - int col_offset; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + int lineno; + int col_offset; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + if (_PyObject_HasAttrId(obj, &PyId_lineno)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_lineno); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &lineno, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &col_offset, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr"); + return 1; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)BoolOp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + boolop_ty op; + asdl_seq* values; + + if (_PyObject_HasAttrId(obj, &PyId_op)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_op); + if (tmp == NULL) goto failed; + res = obj2ast_boolop(tmp, &op, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_lineno)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_lineno); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &lineno, arena); + if (_PyObject_HasAttrId(obj, &PyId_values)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_values); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "BoolOp field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + values = asdl_seq_new(len, arena); + if (values == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(values, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &col_offset, arena); + *out = BoolOp(op, values, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)BinOp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty left; + operator_ty op; + expr_ty right; + + if (_PyObject_HasAttrId(obj, &PyId_left)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_left); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &left, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_op)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_op); + if (tmp == NULL) goto failed; + res = obj2ast_operator(tmp, &op, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_right)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_right); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &right, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp"); + return 1; + } + *out = BinOp(left, op, right, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)UnaryOp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + unaryop_ty op; + expr_ty operand; + + if (_PyObject_HasAttrId(obj, &PyId_op)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_op); + if (tmp == NULL) goto failed; + res = obj2ast_unaryop(tmp, &op, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_operand)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_operand); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &operand, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp"); + return 1; + } + *out = UnaryOp(op, operand, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Lambda_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + arguments_ty args; + expr_ty body; + + if (_PyObject_HasAttrId(obj, &PyId_args)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_args); + if (tmp == NULL) goto failed; + res = obj2ast_arguments(tmp, &args, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &body, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda"); + return 1; + } + *out = Lambda(args, body, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)IfExp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty test; + expr_ty body; + expr_ty orelse; + + if (_PyObject_HasAttrId(obj, &PyId_test)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_test); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &test, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &body, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_orelse)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_orelse); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &orelse, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp"); + return 1; + } + *out = IfExp(test, body, orelse, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Dict_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* keys; + asdl_seq* values; + + if (_PyObject_HasAttrId(obj, &PyId_keys)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_keys); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Dict field \"keys\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + keys = asdl_seq_new(len, arena); + if (keys == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(keys, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)BoolOp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_values)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_values); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Dict field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + values = asdl_seq_new(len, arena); + if (values == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(values, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict"); + return 1; } - if (isinstance) { - boolop_ty op; - asdl_seq* values; - - if (_PyObject_HasAttrId(obj, &PyId_op)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_op); - if (tmp == NULL) goto failed; - res = obj2ast_boolop(tmp, &op, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_values)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_values); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "BoolOp field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - values = asdl_seq_new(len, arena); - if (values == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(values, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp"); - return 1; - } - *out = BoolOp(op, values, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = Dict(keys, values, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Set_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* elts; + + if (_PyObject_HasAttrId(obj, &PyId_elts)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_elts); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Set field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + elts = asdl_seq_new(len, arena); + if (elts == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(elts, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)BinOp_type); - if (isinstance == -1) { - return 1; + *out = Set(elts, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ListComp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty elt; + asdl_seq* generators; + + if (_PyObject_HasAttrId(obj, &PyId_elt)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_elt); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &elt, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp"); + return 1; } - if (isinstance) { - expr_ty left; - operator_ty op; - expr_ty right; - - if (_PyObject_HasAttrId(obj, &PyId_left)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_left); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &left, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_op)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_op); - if (tmp == NULL) goto failed; - res = obj2ast_operator(tmp, &op, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_right)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_right); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &right, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp"); - return 1; - } - *out = BinOp(left, op, right, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_generators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_generators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ListComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + generators = asdl_seq_new(len, arena); + if (generators == NULL) goto failed; + for (i = 0; i < len; i++) { + comprehension_ty value; + res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(generators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)UnaryOp_type); - if (isinstance == -1) { - return 1; + *out = ListComp(elt, generators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)SetComp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty elt; + asdl_seq* generators; + + if (_PyObject_HasAttrId(obj, &PyId_elt)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_elt); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &elt, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp"); + return 1; } - if (isinstance) { - unaryop_ty op; - expr_ty operand; - - if (_PyObject_HasAttrId(obj, &PyId_op)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_op); - if (tmp == NULL) goto failed; - res = obj2ast_unaryop(tmp, &op, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_operand)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_operand); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &operand, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp"); - return 1; - } - *out = UnaryOp(op, operand, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_generators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_generators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "SetComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + generators = asdl_seq_new(len, arena); + if (generators == NULL) goto failed; + for (i = 0; i < len; i++) { + comprehension_ty value; + res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(generators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Lambda_type); - if (isinstance == -1) { - return 1; + *out = SetComp(elt, generators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)DictComp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty key; + expr_ty value; + asdl_seq* generators; + + if (_PyObject_HasAttrId(obj, &PyId_key)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_key); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &key, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp"); + return 1; } - if (isinstance) { - arguments_ty args; - expr_ty body; - - if (_PyObject_HasAttrId(obj, &PyId_args)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_args); - if (tmp == NULL) goto failed; - res = obj2ast_arguments(tmp, &args, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &body, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda"); - return 1; - } - *out = Lambda(args, body, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)IfExp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_generators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_generators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "DictComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + generators = asdl_seq_new(len, arena); + if (generators == NULL) goto failed; + for (i = 0; i < len; i++) { + comprehension_ty value; + res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(generators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp"); + return 1; } - if (isinstance) { - expr_ty test; - expr_ty body; - expr_ty orelse; - - if (_PyObject_HasAttrId(obj, &PyId_test)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_test); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &test, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &body, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_orelse)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_orelse); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &orelse, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp"); - return 1; - } - *out = IfExp(test, body, orelse, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = DictComp(key, value, generators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)GeneratorExp_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty elt; + asdl_seq* generators; + + if (_PyObject_HasAttrId(obj, &PyId_elt)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_elt); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &elt, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Dict_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_generators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_generators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "GeneratorExp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + generators = asdl_seq_new(len, arena); + if (generators == NULL) goto failed; + for (i = 0; i < len; i++) { + comprehension_ty value; + res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(generators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp"); + return 1; } - if (isinstance) { - asdl_seq* keys; - asdl_seq* values; - - if (_PyObject_HasAttrId(obj, &PyId_keys)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_keys); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Dict field \"keys\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - keys = asdl_seq_new(len, arena); - if (keys == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(keys, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_values)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_values); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Dict field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - values = asdl_seq_new(len, arena); - if (values == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(values, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict"); - return 1; - } - *out = Dict(keys, values, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = GeneratorExp(elt, generators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Yield_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (exists_not_none(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + value = NULL; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Set_type); - if (isinstance == -1) { - return 1; + *out = Yield(value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)YieldFrom_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom"); + return 1; } - if (isinstance) { - asdl_seq* elts; - - if (_PyObject_HasAttrId(obj, &PyId_elts)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_elts); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Set field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - elts = asdl_seq_new(len, arena); - if (elts == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(elts, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set"); - return 1; - } - *out = Set(elts, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = YieldFrom(value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Compare_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty left; + asdl_int_seq* ops; + asdl_seq* comparators; + + if (_PyObject_HasAttrId(obj, &PyId_left)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_left); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &left, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)ListComp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_ops)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_ops); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Compare field \"ops\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + ops = asdl_int_seq_new(len, arena); + if (ops == NULL) goto failed; + for (i = 0; i < len; i++) { + cmpop_ty value; + res = obj2ast_cmpop(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(ops, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare"); + return 1; } - if (isinstance) { - expr_ty elt; - asdl_seq* generators; - - if (_PyObject_HasAttrId(obj, &PyId_elt)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_elt); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &elt, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_generators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_generators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ListComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - generators = asdl_seq_new(len, arena); - if (generators == NULL) goto failed; - for (i = 0; i < len; i++) { - comprehension_ty value; - res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(generators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp"); - return 1; - } - *out = ListComp(elt, generators, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_comparators)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_comparators); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Compare field \"comparators\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + comparators = asdl_seq_new(len, arena); + if (comparators == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(comparators, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)SetComp_type); - if (isinstance == -1) { - return 1; + *out = Compare(left, ops, comparators, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Call_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty func; + asdl_seq* args; + asdl_seq* keywords; + expr_ty starargs; + expr_ty kwargs; + + if (_PyObject_HasAttrId(obj, &PyId_func)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_func); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &func, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call"); + return 1; } - if (isinstance) { - expr_ty elt; - asdl_seq* generators; - - if (_PyObject_HasAttrId(obj, &PyId_elt)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_elt); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &elt, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_generators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_generators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "SetComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - generators = asdl_seq_new(len, arena); - if (generators == NULL) goto failed; - for (i = 0; i < len; i++) { - comprehension_ty value; - res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(generators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp"); - return 1; - } - *out = SetComp(elt, generators, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + if (_PyObject_HasAttrId(obj, &PyId_args)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_args); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Call field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + args = asdl_seq_new(len, arena); + if (args == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(args, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)DictComp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_keywords)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_keywords); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Call field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + keywords = asdl_seq_new(len, arena); + if (keywords == NULL) goto failed; + for (i = 0; i < len; i++) { + keyword_ty value; + res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(keywords, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); + return 1; } - if (isinstance) { - expr_ty key; + if (exists_not_none(obj, &PyId_starargs)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_starargs); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &starargs, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + starargs = NULL; + } + if (exists_not_none(obj, &PyId_kwargs)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &kwargs, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + kwargs = NULL; + } + *out = Call(func, args, keywords, starargs, kwargs, lineno, col_offset, + arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Num_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + object n; + + if (_PyObject_HasAttrId(obj, &PyId_n)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_n); + if (tmp == NULL) goto failed; + res = obj2ast_object(tmp, &n, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"n\" missing from Num"); + return 1; + } + *out = Num(n, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Str_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + string s; + + if (_PyObject_HasAttrId(obj, &PyId_s)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_s); + if (tmp == NULL) goto failed; + res = obj2ast_string(tmp, &s, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Str"); + return 1; + } + *out = Str(s, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Bytes_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + bytes s; + + if (_PyObject_HasAttrId(obj, &PyId_s)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_s); + if (tmp == NULL) goto failed; + res = obj2ast_bytes(tmp, &s, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Bytes"); + return 1; + } + *out = Bytes(s, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)NameConstant_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + singleton value; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_singleton(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from NameConstant"); + return 1; + } + *out = NameConstant(value, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Ellipsis_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + + *out = Ellipsis(lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Attribute_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + identifier attr; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_attr)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_attr); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &attr, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute"); + return 1; + } + *out = Attribute(value, attr, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Subscript_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + slice_ty slice; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_slice)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_slice); + if (tmp == NULL) goto failed; + res = obj2ast_slice(tmp, &slice, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript"); + return 1; + } + *out = Subscript(value, slice, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Starred_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred"); + return 1; + } + *out = Starred(value, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Name_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier id; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_id)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_id); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &id, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name"); + return 1; + } + *out = Name(id, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)List_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* elts; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_elts)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_elts); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "List field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + elts = asdl_seq_new(len, arena); + if (elts == NULL) goto failed; + for (i = 0; i < len; i++) { expr_ty value; - asdl_seq* generators; - - if (_PyObject_HasAttrId(obj, &PyId_key)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_key); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &key, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_generators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_generators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "DictComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - generators = asdl_seq_new(len, arena); - if (generators == NULL) goto failed; - for (i = 0; i < len; i++) { - comprehension_ty value; - res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(generators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp"); - return 1; - } - *out = DictComp(key, value, generators, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(elts, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)GeneratorExp_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List"); + return 1; } - if (isinstance) { - expr_ty elt; - asdl_seq* generators; - - if (_PyObject_HasAttrId(obj, &PyId_elt)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_elt); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &elt, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_generators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_generators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "GeneratorExp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - generators = asdl_seq_new(len, arena); - if (generators == NULL) goto failed; - for (i = 0; i < len; i++) { - comprehension_ty value; - res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(generators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp"); - return 1; - } - *out = GeneratorExp(elt, generators, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; + *out = List(elts, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Tuple_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* elts; + expr_context_ty ctx; + + if (_PyObject_HasAttrId(obj, &PyId_elts)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_elts); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "Tuple field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + elts = asdl_seq_new(len, arena); + if (elts == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(elts, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Yield_type); - if (isinstance == -1) { - return 1; + if (_PyObject_HasAttrId(obj, &PyId_ctx)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_ctx); + if (tmp == NULL) goto failed; + res = obj2ast_expr_context(tmp, &ctx, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple"); + return 1; } - if (isinstance) { - expr_ty value; - - if (exists_not_none(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - value = NULL; - } - *out = Yield(value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)YieldFrom_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom"); - return 1; - } - *out = YieldFrom(value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Compare_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty left; - asdl_int_seq* ops; - asdl_seq* comparators; - - if (_PyObject_HasAttrId(obj, &PyId_left)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_left); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &left, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ops)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_ops); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Compare field \"ops\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - ops = asdl_int_seq_new(len, arena); - if (ops == NULL) goto failed; - for (i = 0; i < len; i++) { - cmpop_ty value; - res = obj2ast_cmpop(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(ops, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_comparators)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_comparators); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Compare field \"comparators\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - comparators = asdl_seq_new(len, arena); - if (comparators == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(comparators, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare"); - return 1; - } - *out = Compare(left, ops, comparators, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Call_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty func; - asdl_seq* args; - asdl_seq* keywords; - expr_ty starargs; - expr_ty kwargs; - - if (_PyObject_HasAttrId(obj, &PyId_func)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_func); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &func, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_args)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_args); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Call field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - args = asdl_seq_new(len, arena); - if (args == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(args, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_keywords)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_keywords); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Call field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - keywords = asdl_seq_new(len, arena); - if (keywords == NULL) goto failed; - for (i = 0; i < len; i++) { - keyword_ty value; - res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(keywords, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); - return 1; - } - if (exists_not_none(obj, &PyId_starargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_starargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &starargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - starargs = NULL; - } - if (exists_not_none(obj, &PyId_kwargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &kwargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - kwargs = NULL; - } - *out = Call(func, args, keywords, starargs, kwargs, lineno, - col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Num_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - object n; - - if (_PyObject_HasAttrId(obj, &PyId_n)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_n); - if (tmp == NULL) goto failed; - res = obj2ast_object(tmp, &n, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"n\" missing from Num"); - return 1; - } - *out = Num(n, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Str_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - string s; - - if (_PyObject_HasAttrId(obj, &PyId_s)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_s); - if (tmp == NULL) goto failed; - res = obj2ast_string(tmp, &s, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Str"); - return 1; - } - *out = Str(s, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Bytes_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - bytes s; - - if (_PyObject_HasAttrId(obj, &PyId_s)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_s); - if (tmp == NULL) goto failed; - res = obj2ast_bytes(tmp, &s, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Bytes"); - return 1; - } - *out = Bytes(s, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)NameConstant_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - singleton value; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_singleton(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from NameConstant"); - return 1; - } - *out = NameConstant(value, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Ellipsis_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - - *out = Ellipsis(lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Attribute_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - identifier attr; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_attr)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_attr); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &attr, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute"); - return 1; - } - *out = Attribute(value, attr, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Subscript_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - slice_ty slice; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_slice)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_slice); - if (tmp == NULL) goto failed; - res = obj2ast_slice(tmp, &slice, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript"); - return 1; - } - *out = Subscript(value, slice, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Starred_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred"); - return 1; - } - *out = Starred(value, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Name_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - identifier id; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_id)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_id); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &id, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name"); - return 1; - } - *out = Name(id, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)List_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - asdl_seq* elts; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_elts)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_elts); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "List field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - elts = asdl_seq_new(len, arena); - if (elts == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(elts, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List"); - return 1; - } - *out = List(elts, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)Tuple_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - asdl_seq* elts; - expr_context_ty ctx; - - if (_PyObject_HasAttrId(obj, &PyId_elts)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_elts); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "Tuple field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - elts = asdl_seq_new(len, arena); - if (elts == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(elts, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_ctx)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_ctx); - if (tmp == NULL) goto failed; - res = obj2ast_expr_context(tmp, &ctx, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple"); - return 1; - } - *out = Tuple(elts, ctx, lineno, col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of expr, but got %R", obj); - failed: - Py_XDECREF(tmp); - return 1; + *out = Tuple(elts, ctx, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of expr, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_expr_context(PyObject* obj, expr_context_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)Load_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Load; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Store_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Store; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Del_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Del; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)AugLoad_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = AugLoad; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)AugStore_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = AugStore; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Param_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Param; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of expr_context, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)Load_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = Load; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Store_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Store; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Del_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Del; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)AugLoad_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = AugLoad; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)AugStore_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = AugStore; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Param_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Param; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of expr_context, but got %R", obj); + return 1; } int obj2ast_slice(PyObject* obj, slice_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Slice_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty lower; + expr_ty upper; + expr_ty step; + + if (exists_not_none(obj, &PyId_lower)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_lower); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &lower, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + lower = NULL; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Slice_type); - if (isinstance == -1) { - return 1; + if (exists_not_none(obj, &PyId_upper)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_upper); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &upper, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + upper = NULL; } - if (isinstance) { - expr_ty lower; - expr_ty upper; - expr_ty step; - - if (exists_not_none(obj, &PyId_lower)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_lower); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &lower, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - lower = NULL; - } - if (exists_not_none(obj, &PyId_upper)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_upper); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &upper, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - upper = NULL; - } - if (exists_not_none(obj, &PyId_step)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_step); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &step, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - step = NULL; - } - *out = Slice(lower, upper, step, arena); - if (*out == NULL) goto failed; - return 0; + if (exists_not_none(obj, &PyId_step)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_step); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &step, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + step = NULL; } - isinstance = PyObject_IsInstance(obj, (PyObject*)ExtSlice_type); - if (isinstance == -1) { - return 1; + *out = Slice(lower, upper, step, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ExtSlice_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_seq* dims; + + if (_PyObject_HasAttrId(obj, &PyId_dims)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_dims); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ExtSlice field \"dims\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + dims = asdl_seq_new(len, arena); + if (dims == NULL) goto failed; + for (i = 0; i < len; i++) { + slice_ty value; + res = obj2ast_slice(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(dims, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"dims\" missing from ExtSlice"); + return 1; } - if (isinstance) { - asdl_seq* dims; - - if (_PyObject_HasAttrId(obj, &PyId_dims)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_dims); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ExtSlice field \"dims\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - dims = asdl_seq_new(len, arena); - if (dims == NULL) goto failed; - for (i = 0; i < len; i++) { - slice_ty value; - res = obj2ast_slice(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(dims, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"dims\" missing from ExtSlice"); - return 1; - } - *out = ExtSlice(dims, arena); - if (*out == NULL) goto failed; - return 0; + *out = ExtSlice(dims, arena); + if (*out == NULL) goto failed; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)Index_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Index"); + return 1; } - isinstance = PyObject_IsInstance(obj, (PyObject*)Index_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Index"); - return 1; - } - *out = Index(value, arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of slice, but got %R", obj); - failed: - Py_XDECREF(tmp); - return 1; + *out = Index(value, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of slice, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_boolop(PyObject* obj, boolop_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)And_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = And; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Or_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Or; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of boolop, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)And_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = And; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Or_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Or; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of boolop, but got %R", obj); + return 1; } int obj2ast_operator(PyObject* obj, operator_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)Add_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Add; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Sub_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Sub; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Mult_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Mult; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Div_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Div; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Mod_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Mod; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Pow_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Pow; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)LShift_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = LShift; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)RShift_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = RShift; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)BitOr_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = BitOr; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)BitXor_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = BitXor; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)BitAnd_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = BitAnd; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)FloorDiv_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = FloorDiv; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of operator, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)Add_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = Add; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Sub_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Sub; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Mult_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Mult; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Div_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Div; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Mod_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Mod; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Pow_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Pow; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)LShift_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = LShift; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)RShift_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = RShift; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)BitOr_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = BitOr; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)BitXor_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = BitXor; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)BitAnd_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = BitAnd; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)FloorDiv_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = FloorDiv; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of operator, but got %R", obj); + return 1; } int obj2ast_unaryop(PyObject* obj, unaryop_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)Invert_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Invert; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Not_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Not; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)UAdd_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = UAdd; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)USub_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = USub; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of unaryop, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)Invert_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = Invert; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Not_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Not; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)UAdd_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = UAdd; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)USub_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = USub; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of unaryop, but got %R", obj); + return 1; } int obj2ast_cmpop(PyObject* obj, cmpop_ty* out, PyArena* arena) { - int isinstance; - - isinstance = PyObject_IsInstance(obj, (PyObject *)Eq_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Eq; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)NotEq_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = NotEq; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Lt_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Lt; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)LtE_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = LtE; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Gt_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Gt; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)GtE_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = GtE; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)Is_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = Is; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)IsNot_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = IsNot; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)In_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = In; - return 0; - } - isinstance = PyObject_IsInstance(obj, (PyObject *)NotIn_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - *out = NotIn; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of cmpop, but got %R", obj); + int isinstance; + + isinstance = PyObject_IsInstance(obj, (PyObject *)Eq_type); + if (isinstance == -1) { return 1; + } + if (isinstance) { + *out = Eq; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)NotEq_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = NotEq; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Lt_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Lt; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)LtE_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = LtE; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Gt_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Gt; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)GtE_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = GtE; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)Is_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = Is; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)IsNot_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = IsNot; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)In_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = In; + return 0; + } + isinstance = PyObject_IsInstance(obj, (PyObject *)NotIn_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + *out = NotIn; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of cmpop, but got %R", obj); + return 1; } int obj2ast_comprehension(PyObject* obj, comprehension_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - expr_ty target; - expr_ty iter; - asdl_seq* ifs; - - if (_PyObject_HasAttrId(obj, &PyId_target)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_target); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &target, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension"); - return 1; + PyObject* tmp = NULL; + expr_ty target; + expr_ty iter; + asdl_seq* ifs; + + if (_PyObject_HasAttrId(obj, &PyId_target)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_target); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &target, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_iter)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_iter); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &iter, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_ifs)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_ifs); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "comprehension field \"ifs\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; } - if (_PyObject_HasAttrId(obj, &PyId_iter)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_iter); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &iter, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension"); - return 1; + len = PyList_GET_SIZE(tmp); + ifs = asdl_seq_new(len, arena); + if (ifs == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(ifs, i, value); } - if (_PyObject_HasAttrId(obj, &PyId_ifs)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_ifs); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "comprehension field \"ifs\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - ifs = asdl_seq_new(len, arena); - if (ifs == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(ifs, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension"); - return 1; - } - *out = comprehension(target, iter, ifs, arena); - return 0; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension"); + return 1; + } + *out = comprehension(target, iter, ifs, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_excepthandler(PyObject* obj, excepthandler_ty* out, PyArena* arena) { - int isinstance; - - PyObject *tmp = NULL; - int lineno; - int col_offset; - - if (obj == Py_None) { - *out = NULL; - return 0; + int isinstance; + + PyObject *tmp = NULL; + int lineno; + int col_offset; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + if (_PyObject_HasAttrId(obj, &PyId_lineno)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_lineno); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &lineno, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); + if (tmp == NULL) goto failed; + res = obj2ast_int(tmp, &col_offset, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler"); + return 1; + } + isinstance = PyObject_IsInstance(obj, (PyObject*)ExceptHandler_type); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty type; + identifier name; + asdl_seq* body; + + if (exists_not_none(obj, &PyId_type)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_type); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &type, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + type = NULL; } - if (_PyObject_HasAttrId(obj, &PyId_lineno)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_lineno); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &lineno, arena); + if (exists_not_none(obj, &PyId_name)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_name); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &name, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + name = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_body)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_body); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ExceptHandler field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + body = asdl_seq_new(len, arena); + if (body == NULL) goto failed; + for (i = 0; i < len; i++) { + stmt_ty value; + res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + asdl_seq_SET(body, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler"); - return 1; + PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler"); + return 1; } - if (_PyObject_HasAttrId(obj, &PyId_col_offset)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_col_offset); - if (tmp == NULL) goto failed; - res = obj2ast_int(tmp, &col_offset, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler"); - return 1; - } - isinstance = PyObject_IsInstance(obj, (PyObject*)ExceptHandler_type); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty type; - identifier name; - asdl_seq* body; - - if (exists_not_none(obj, &PyId_type)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_type); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &type, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - type = NULL; - } - if (exists_not_none(obj, &PyId_name)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_name); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &name, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - name = NULL; - } - if (_PyObject_HasAttrId(obj, &PyId_body)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_body); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ExceptHandler field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - body = asdl_seq_new(len, arena); - if (body == NULL) goto failed; - for (i = 0; i < len; i++) { - stmt_ty value; - res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(body, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler"); - return 1; - } - *out = ExceptHandler(type, name, body, lineno, col_offset, - arena); - if (*out == NULL) goto failed; - return 0; - } - - PyErr_Format(PyExc_TypeError, "expected some sort of excepthandler, but got %R", obj); - failed: - Py_XDECREF(tmp); - return 1; + *out = ExceptHandler(type, name, body, lineno, col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of excepthandler, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; } int obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - asdl_seq* args; - arg_ty vararg; - asdl_seq* kwonlyargs; - asdl_seq* kw_defaults; - arg_ty kwarg; - asdl_seq* defaults; - - if (_PyObject_HasAttrId(obj, &PyId_args)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_args); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "arguments field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - args = asdl_seq_new(len, arena); - if (args == NULL) goto failed; - for (i = 0; i < len; i++) { - arg_ty value; - res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(args, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments"); - return 1; + PyObject* tmp = NULL; + asdl_seq* args; + arg_ty vararg; + asdl_seq* kwonlyargs; + asdl_seq* kw_defaults; + arg_ty kwarg; + asdl_seq* defaults; + + if (_PyObject_HasAttrId(obj, &PyId_args)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_args); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "arguments field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; } - if (exists_not_none(obj, &PyId_vararg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_vararg); - if (tmp == NULL) goto failed; - res = obj2ast_arg(tmp, &vararg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - vararg = NULL; + len = PyList_GET_SIZE(tmp); + args = asdl_seq_new(len, arena); + if (args == NULL) goto failed; + for (i = 0; i < len; i++) { + arg_ty value; + res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(args, i, value); } - if (_PyObject_HasAttrId(obj, &PyId_kwonlyargs)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_kwonlyargs); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "arguments field \"kwonlyargs\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - kwonlyargs = asdl_seq_new(len, arena); - if (kwonlyargs == NULL) goto failed; - for (i = 0; i < len; i++) { - arg_ty value; - res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(kwonlyargs, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments"); - return 1; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments"); + return 1; + } + if (exists_not_none(obj, &PyId_vararg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_vararg); + if (tmp == NULL) goto failed; + res = obj2ast_arg(tmp, &vararg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + vararg = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_kwonlyargs)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_kwonlyargs); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "arguments field \"kwonlyargs\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; } - if (_PyObject_HasAttrId(obj, &PyId_kw_defaults)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_kw_defaults); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "arguments field \"kw_defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - kw_defaults = asdl_seq_new(len, arena); - if (kw_defaults == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(kw_defaults, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments"); - return 1; + len = PyList_GET_SIZE(tmp); + kwonlyargs = asdl_seq_new(len, arena); + if (kwonlyargs == NULL) goto failed; + for (i = 0; i < len; i++) { + arg_ty value; + res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(kwonlyargs, i, value); } - if (exists_not_none(obj, &PyId_kwarg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_kwarg); - if (tmp == NULL) goto failed; - res = obj2ast_arg(tmp, &kwarg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - kwarg = NULL; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_kw_defaults)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_kw_defaults); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "arguments field \"kw_defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; } - if (_PyObject_HasAttrId(obj, &PyId_defaults)) { - int res; - Py_ssize_t len; - Py_ssize_t i; - tmp = _PyObject_GetAttrId(obj, &PyId_defaults); - if (tmp == NULL) goto failed; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "arguments field \"defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name); - goto failed; - } - len = PyList_GET_SIZE(tmp); - defaults = asdl_seq_new(len, arena); - if (defaults == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty value; - res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); - if (res != 0) goto failed; - asdl_seq_SET(defaults, i, value); - } - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments"); - return 1; + len = PyList_GET_SIZE(tmp); + kw_defaults = asdl_seq_new(len, arena); + if (kw_defaults == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(kw_defaults, i, value); } - *out = arguments(args, vararg, kwonlyargs, kw_defaults, kwarg, - defaults, arena); - return 0; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments"); + return 1; + } + if (exists_not_none(obj, &PyId_kwarg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_kwarg); + if (tmp == NULL) goto failed; + res = obj2ast_arg(tmp, &kwarg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + kwarg = NULL; + } + if (_PyObject_HasAttrId(obj, &PyId_defaults)) { + int res; + Py_ssize_t len; + Py_ssize_t i; + tmp = _PyObject_GetAttrId(obj, &PyId_defaults); + if (tmp == NULL) goto failed; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "arguments field \"defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name); + goto failed; + } + len = PyList_GET_SIZE(tmp); + defaults = asdl_seq_new(len, arena); + if (defaults == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty value; + res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); + if (res != 0) goto failed; + asdl_seq_SET(defaults, i, value); + } + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments"); + return 1; + } + *out = arguments(args, vararg, kwonlyargs, kw_defaults, kwarg, defaults, + arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_arg(PyObject* obj, arg_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - identifier arg; - expr_ty annotation; - - if (_PyObject_HasAttrId(obj, &PyId_arg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_arg); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &arg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg"); - return 1; - } - if (exists_not_none(obj, &PyId_annotation)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_annotation); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &annotation, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - annotation = NULL; - } - *out = arg(arg, annotation, arena); - return 0; + PyObject* tmp = NULL; + identifier arg; + expr_ty annotation; + + if (_PyObject_HasAttrId(obj, &PyId_arg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_arg); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &arg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg"); + return 1; + } + if (exists_not_none(obj, &PyId_annotation)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_annotation); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &annotation, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + annotation = NULL; + } + *out = arg(arg, annotation, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_keyword(PyObject* obj, keyword_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - identifier arg; - expr_ty value; - - if (_PyObject_HasAttrId(obj, &PyId_arg)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_arg); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &arg, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from keyword"); - return 1; - } - if (_PyObject_HasAttrId(obj, &PyId_value)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_value); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &value, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword"); - return 1; - } - *out = keyword(arg, value, arena); - return 0; + PyObject* tmp = NULL; + identifier arg; + expr_ty value; + + if (_PyObject_HasAttrId(obj, &PyId_arg)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_arg); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &arg, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from keyword"); + return 1; + } + if (_PyObject_HasAttrId(obj, &PyId_value)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_value); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword"); + return 1; + } + *out = keyword(arg, value, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_alias(PyObject* obj, alias_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - identifier name; - identifier asname; - - if (_PyObject_HasAttrId(obj, &PyId_name)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_name); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &name, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias"); - return 1; - } - if (exists_not_none(obj, &PyId_asname)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_asname); - if (tmp == NULL) goto failed; - res = obj2ast_identifier(tmp, &asname, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - asname = NULL; - } - *out = alias(name, asname, arena); - return 0; + PyObject* tmp = NULL; + identifier name; + identifier asname; + + if (_PyObject_HasAttrId(obj, &PyId_name)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_name); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &name, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias"); + return 1; + } + if (exists_not_none(obj, &PyId_asname)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_asname); + if (tmp == NULL) goto failed; + res = obj2ast_identifier(tmp, &asname, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + asname = NULL; + } + *out = alias(name, asname, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } int obj2ast_withitem(PyObject* obj, withitem_ty* out, PyArena* arena) { - PyObject* tmp = NULL; - expr_ty context_expr; - expr_ty optional_vars; - - if (_PyObject_HasAttrId(obj, &PyId_context_expr)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_context_expr); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &context_expr, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem"); - return 1; - } - if (exists_not_none(obj, &PyId_optional_vars)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_optional_vars); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &optional_vars, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - optional_vars = NULL; - } - *out = withitem(context_expr, optional_vars, arena); - return 0; + PyObject* tmp = NULL; + expr_ty context_expr; + expr_ty optional_vars; + + if (_PyObject_HasAttrId(obj, &PyId_context_expr)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_context_expr); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &context_expr, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem"); + return 1; + } + if (exists_not_none(obj, &PyId_optional_vars)) { + int res; + tmp = _PyObject_GetAttrId(obj, &PyId_optional_vars); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &optional_vars, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + optional_vars = NULL; + } + *out = withitem(context_expr, optional_vars, arena); + return 0; failed: - Py_XDECREF(tmp); - return 1; + Py_XDECREF(tmp); + return 1; } @@ -6970,219 +6956,188 @@ PyMODINIT_FUNC PyInit__ast(void) { - PyObject *m, *d; - if (!init_types()) return NULL; - m = PyModule_Create(&_astmodule); - if (!m) return NULL; - d = PyModule_GetDict(m); - if (PyDict_SetItemString(d, "AST", (PyObject*)&AST_type) < 0) return - NULL; - if (PyModule_AddIntMacro(m, PyCF_ONLY_AST) < 0) - return NULL; - if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Interactive", (PyObject*)Interactive_type) - < 0) return NULL; - if (PyDict_SetItemString(d, "Expression", (PyObject*)Expression_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Suite", (PyObject*)Suite_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "stmt", (PyObject*)stmt_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "FunctionDef", (PyObject*)FunctionDef_type) - < 0) return NULL; - if (PyDict_SetItemString(d, "ClassDef", (PyObject*)ClassDef_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Return", (PyObject*)Return_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Delete", (PyObject*)Delete_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Assign", (PyObject*)Assign_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "AugAssign", (PyObject*)AugAssign_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "For", (PyObject*)For_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "While", (PyObject*)While_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "If", (PyObject*)If_type) < 0) return NULL; - if (PyDict_SetItemString(d, "With", (PyObject*)With_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Raise", (PyObject*)Raise_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Try", (PyObject*)Try_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Assert", (PyObject*)Assert_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Import", (PyObject*)Import_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "ImportFrom", (PyObject*)ImportFrom_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Global", (PyObject*)Global_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Nonlocal", (PyObject*)Nonlocal_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Expr", (PyObject*)Expr_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Pass", (PyObject*)Pass_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Break", (PyObject*)Break_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Continue", (PyObject*)Continue_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "expr", (PyObject*)expr_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "BoolOp", (PyObject*)BoolOp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "BinOp", (PyObject*)BinOp_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "UnaryOp", (PyObject*)UnaryOp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Lambda", (PyObject*)Lambda_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "IfExp", (PyObject*)IfExp_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Dict", (PyObject*)Dict_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Set", (PyObject*)Set_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "ListComp", (PyObject*)ListComp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "SetComp", (PyObject*)SetComp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "DictComp", (PyObject*)DictComp_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "GeneratorExp", - (PyObject*)GeneratorExp_type) < 0) return NULL; - if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "YieldFrom", (PyObject*)YieldFrom_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Compare", (PyObject*)Compare_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Call", (PyObject*)Call_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Num", (PyObject*)Num_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Str", (PyObject*)Str_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Bytes", (PyObject*)Bytes_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "NameConstant", - (PyObject*)NameConstant_type) < 0) return NULL; - if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Subscript", (PyObject*)Subscript_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "Starred", (PyObject*)Starred_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Name", (PyObject*)Name_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "List", (PyObject*)List_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Tuple", (PyObject*)Tuple_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "expr_context", - (PyObject*)expr_context_type) < 0) return NULL; - if (PyDict_SetItemString(d, "Load", (PyObject*)Load_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Store", (PyObject*)Store_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Del", (PyObject*)Del_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "AugLoad", (PyObject*)AugLoad_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "AugStore", (PyObject*)AugStore_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Param", (PyObject*)Param_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "slice", (PyObject*)slice_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Slice", (PyObject*)Slice_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "ExtSlice", (PyObject*)ExtSlice_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Index", (PyObject*)Index_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "boolop", (PyObject*)boolop_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "And", (PyObject*)And_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Or", (PyObject*)Or_type) < 0) return NULL; - if (PyDict_SetItemString(d, "operator", (PyObject*)operator_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Add", (PyObject*)Add_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Sub", (PyObject*)Sub_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Mult", (PyObject*)Mult_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Div", (PyObject*)Div_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Mod", (PyObject*)Mod_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Pow", (PyObject*)Pow_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "LShift", (PyObject*)LShift_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "RShift", (PyObject*)RShift_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "BitOr", (PyObject*)BitOr_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "BitXor", (PyObject*)BitXor_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "BitAnd", (PyObject*)BitAnd_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "FloorDiv", (PyObject*)FloorDiv_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "unaryop", (PyObject*)unaryop_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Invert", (PyObject*)Invert_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "Not", (PyObject*)Not_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "UAdd", (PyObject*)UAdd_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "USub", (PyObject*)USub_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "cmpop", (PyObject*)cmpop_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Eq", (PyObject*)Eq_type) < 0) return NULL; - if (PyDict_SetItemString(d, "NotEq", (PyObject*)NotEq_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Lt", (PyObject*)Lt_type) < 0) return NULL; - if (PyDict_SetItemString(d, "LtE", (PyObject*)LtE_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Gt", (PyObject*)Gt_type) < 0) return NULL; - if (PyDict_SetItemString(d, "GtE", (PyObject*)GtE_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "Is", (PyObject*)Is_type) < 0) return NULL; - if (PyDict_SetItemString(d, "IsNot", (PyObject*)IsNot_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "In", (PyObject*)In_type) < 0) return NULL; - if (PyDict_SetItemString(d, "NotIn", (PyObject*)NotIn_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "comprehension", - (PyObject*)comprehension_type) < 0) return NULL; - if (PyDict_SetItemString(d, "excepthandler", - (PyObject*)excepthandler_type) < 0) return NULL; - if (PyDict_SetItemString(d, "ExceptHandler", - (PyObject*)ExceptHandler_type) < 0) return NULL; - if (PyDict_SetItemString(d, "arguments", (PyObject*)arguments_type) < - 0) return NULL; - if (PyDict_SetItemString(d, "arg", (PyObject*)arg_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "keyword", (PyObject*)keyword_type) < 0) - return NULL; - if (PyDict_SetItemString(d, "alias", (PyObject*)alias_type) < 0) return - NULL; - if (PyDict_SetItemString(d, "withitem", (PyObject*)withitem_type) < 0) - return NULL; - return m; + PyObject *m, *d; + if (!init_types()) return NULL; + m = PyModule_Create(&_astmodule); + if (!m) return NULL; + d = PyModule_GetDict(m); + if (PyDict_SetItemString(d, "AST", (PyObject*)&AST_type) < 0) return NULL; + if (PyModule_AddIntMacro(m, PyCF_ONLY_AST) < 0) + return NULL; + if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Interactive", (PyObject*)Interactive_type) < + 0) return NULL; + if (PyDict_SetItemString(d, "Expression", (PyObject*)Expression_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Suite", (PyObject*)Suite_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "stmt", (PyObject*)stmt_type) < 0) return NULL; + if (PyDict_SetItemString(d, "FunctionDef", (PyObject*)FunctionDef_type) < + 0) return NULL; + if (PyDict_SetItemString(d, "ClassDef", (PyObject*)ClassDef_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Return", (PyObject*)Return_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Delete", (PyObject*)Delete_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Assign", (PyObject*)Assign_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "AugAssign", (PyObject*)AugAssign_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "For", (PyObject*)For_type) < 0) return NULL; + if (PyDict_SetItemString(d, "While", (PyObject*)While_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "If", (PyObject*)If_type) < 0) return NULL; + if (PyDict_SetItemString(d, "With", (PyObject*)With_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Raise", (PyObject*)Raise_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Try", (PyObject*)Try_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Assert", (PyObject*)Assert_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Import", (PyObject*)Import_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "ImportFrom", (PyObject*)ImportFrom_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Global", (PyObject*)Global_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Nonlocal", (PyObject*)Nonlocal_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Expr", (PyObject*)Expr_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Pass", (PyObject*)Pass_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Break", (PyObject*)Break_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Continue", (PyObject*)Continue_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "expr", (PyObject*)expr_type) < 0) return NULL; + if (PyDict_SetItemString(d, "BoolOp", (PyObject*)BoolOp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "BinOp", (PyObject*)BinOp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "UnaryOp", (PyObject*)UnaryOp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Lambda", (PyObject*)Lambda_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "IfExp", (PyObject*)IfExp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Dict", (PyObject*)Dict_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Set", (PyObject*)Set_type) < 0) return NULL; + if (PyDict_SetItemString(d, "ListComp", (PyObject*)ListComp_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "SetComp", (PyObject*)SetComp_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "DictComp", (PyObject*)DictComp_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "GeneratorExp", (PyObject*)GeneratorExp_type) < + 0) return NULL; + if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "YieldFrom", (PyObject*)YieldFrom_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Compare", (PyObject*)Compare_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Call", (PyObject*)Call_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Num", (PyObject*)Num_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Str", (PyObject*)Str_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Bytes", (PyObject*)Bytes_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "NameConstant", (PyObject*)NameConstant_type) < + 0) return NULL; + if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Subscript", (PyObject*)Subscript_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Starred", (PyObject*)Starred_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Name", (PyObject*)Name_type) < 0) return NULL; + if (PyDict_SetItemString(d, "List", (PyObject*)List_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Tuple", (PyObject*)Tuple_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "expr_context", (PyObject*)expr_context_type) < + 0) return NULL; + if (PyDict_SetItemString(d, "Load", (PyObject*)Load_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Store", (PyObject*)Store_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Del", (PyObject*)Del_type) < 0) return NULL; + if (PyDict_SetItemString(d, "AugLoad", (PyObject*)AugLoad_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "AugStore", (PyObject*)AugStore_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Param", (PyObject*)Param_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "slice", (PyObject*)slice_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Slice", (PyObject*)Slice_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "ExtSlice", (PyObject*)ExtSlice_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Index", (PyObject*)Index_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "boolop", (PyObject*)boolop_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "And", (PyObject*)And_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Or", (PyObject*)Or_type) < 0) return NULL; + if (PyDict_SetItemString(d, "operator", (PyObject*)operator_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "Add", (PyObject*)Add_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Sub", (PyObject*)Sub_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Mult", (PyObject*)Mult_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Div", (PyObject*)Div_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Mod", (PyObject*)Mod_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Pow", (PyObject*)Pow_type) < 0) return NULL; + if (PyDict_SetItemString(d, "LShift", (PyObject*)LShift_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "RShift", (PyObject*)RShift_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "BitOr", (PyObject*)BitOr_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "BitXor", (PyObject*)BitXor_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "BitAnd", (PyObject*)BitAnd_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "FloorDiv", (PyObject*)FloorDiv_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "unaryop", (PyObject*)unaryop_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Invert", (PyObject*)Invert_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Not", (PyObject*)Not_type) < 0) return NULL; + if (PyDict_SetItemString(d, "UAdd", (PyObject*)UAdd_type) < 0) return NULL; + if (PyDict_SetItemString(d, "USub", (PyObject*)USub_type) < 0) return NULL; + if (PyDict_SetItemString(d, "cmpop", (PyObject*)cmpop_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Eq", (PyObject*)Eq_type) < 0) return NULL; + if (PyDict_SetItemString(d, "NotEq", (PyObject*)NotEq_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "Lt", (PyObject*)Lt_type) < 0) return NULL; + if (PyDict_SetItemString(d, "LtE", (PyObject*)LtE_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Gt", (PyObject*)Gt_type) < 0) return NULL; + if (PyDict_SetItemString(d, "GtE", (PyObject*)GtE_type) < 0) return NULL; + if (PyDict_SetItemString(d, "Is", (PyObject*)Is_type) < 0) return NULL; + if (PyDict_SetItemString(d, "IsNot", (PyObject*)IsNot_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "In", (PyObject*)In_type) < 0) return NULL; + if (PyDict_SetItemString(d, "NotIn", (PyObject*)NotIn_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "comprehension", (PyObject*)comprehension_type) + < 0) return NULL; + if (PyDict_SetItemString(d, "excepthandler", (PyObject*)excepthandler_type) + < 0) return NULL; + if (PyDict_SetItemString(d, "ExceptHandler", (PyObject*)ExceptHandler_type) + < 0) return NULL; + if (PyDict_SetItemString(d, "arguments", (PyObject*)arguments_type) < 0) + return NULL; + if (PyDict_SetItemString(d, "arg", (PyObject*)arg_type) < 0) return NULL; + if (PyDict_SetItemString(d, "keyword", (PyObject*)keyword_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "alias", (PyObject*)alias_type) < 0) return + NULL; + if (PyDict_SetItemString(d, "withitem", (PyObject*)withitem_type) < 0) + return NULL; + return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 00:04:55 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 00:04:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogUGFyc2VyL2FzZGxf?= =?utf-8?b?Yy5weTogdXNlIFB5X0NMRUFSKCk=?= Message-ID: <3c248l28czz7Ljl@mail.python.org> http://hg.python.org/cpython/rev/d14f40c87438 changeset: 84852:d14f40c87438 branch: 3.3 parent: 84850:f2d557484906 user: Victor Stinner date: Sat Jul 27 00:03:47 2013 +0200 summary: Parser/asdl_c.py: use Py_CLEAR() files: Parser/asdl_c.py | 3 +- Python/Python-ast.c | 402 ++++++++++--------------------- 2 files changed, 135 insertions(+), 270 deletions(-) diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -526,8 +526,7 @@ (field.type, field.name), depth+1) self.emit("if (res != 0) goto failed;", depth+1) - self.emit("Py_XDECREF(tmp);", depth+1) - self.emit("tmp = NULL;", depth+1) + self.emit("Py_CLEAR(tmp);", depth+1) self.emit("} else {", depth) if not field.opt: message = "required field \\\"%s\\\" missing from %s" % (field.name, name) diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -3553,8 +3553,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module"); return 1; @@ -3589,8 +3588,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive"); return 1; @@ -3612,8 +3610,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &body, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression"); return 1; @@ -3648,8 +3645,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Suite"); return 1; @@ -3684,8 +3680,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &lineno, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt"); return 1; @@ -3696,8 +3691,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &col_offset, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt"); return 1; @@ -3719,8 +3713,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &name, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef"); return 1; @@ -3731,8 +3724,7 @@ if (tmp == NULL) goto failed; res = obj2ast_arguments(tmp, &args, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef"); return 1; @@ -3756,8 +3748,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef"); return 1; @@ -3781,8 +3772,7 @@ if (res != 0) goto failed; asdl_seq_SET(decorator_list, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef"); return 1; @@ -3793,8 +3783,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &returns, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { returns = NULL; } @@ -3822,8 +3811,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &name, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef"); return 1; @@ -3847,8 +3835,7 @@ if (res != 0) goto failed; asdl_seq_SET(bases, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef"); return 1; @@ -3872,8 +3859,7 @@ if (res != 0) goto failed; asdl_seq_SET(keywords, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); return 1; @@ -3884,8 +3870,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &starargs, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { starargs = NULL; } @@ -3895,8 +3880,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &kwargs, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { kwargs = NULL; } @@ -3919,8 +3903,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef"); return 1; @@ -3944,8 +3927,7 @@ if (res != 0) goto failed; asdl_seq_SET(decorator_list, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef"); return 1; @@ -3968,8 +3950,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { value = NULL; } @@ -4003,8 +3984,7 @@ if (res != 0) goto failed; asdl_seq_SET(targets, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete"); return 1; @@ -4040,8 +4020,7 @@ if (res != 0) goto failed; asdl_seq_SET(targets, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign"); return 1; @@ -4052,8 +4031,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign"); return 1; @@ -4077,8 +4055,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &target, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign"); return 1; @@ -4089,8 +4066,7 @@ if (tmp == NULL) goto failed; res = obj2ast_operator(tmp, &op, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign"); return 1; @@ -4101,8 +4077,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign"); return 1; @@ -4127,8 +4102,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &target, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For"); return 1; @@ -4139,8 +4113,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &iter, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For"); return 1; @@ -4164,8 +4137,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For"); return 1; @@ -4189,8 +4161,7 @@ if (res != 0) goto failed; asdl_seq_SET(orelse, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For"); return 1; @@ -4214,8 +4185,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &test, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While"); return 1; @@ -4239,8 +4209,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While"); return 1; @@ -4264,8 +4233,7 @@ if (res != 0) goto failed; asdl_seq_SET(orelse, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While"); return 1; @@ -4289,8 +4257,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &test, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If"); return 1; @@ -4314,8 +4281,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If"); return 1; @@ -4339,8 +4305,7 @@ if (res != 0) goto failed; asdl_seq_SET(orelse, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If"); return 1; @@ -4376,8 +4341,7 @@ if (res != 0) goto failed; asdl_seq_SET(items, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With"); return 1; @@ -4401,8 +4365,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With"); return 1; @@ -4425,8 +4388,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &exc, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { exc = NULL; } @@ -4436,8 +4398,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &cause, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { cause = NULL; } @@ -4474,8 +4435,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try"); return 1; @@ -4499,8 +4459,7 @@ if (res != 0) goto failed; asdl_seq_SET(handlers, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try"); return 1; @@ -4524,8 +4483,7 @@ if (res != 0) goto failed; asdl_seq_SET(orelse, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try"); return 1; @@ -4549,8 +4507,7 @@ if (res != 0) goto failed; asdl_seq_SET(finalbody, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try"); return 1; @@ -4574,8 +4531,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &test, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert"); return 1; @@ -4586,8 +4542,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &msg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { msg = NULL; } @@ -4621,8 +4576,7 @@ if (res != 0) goto failed; asdl_seq_SET(names, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import"); return 1; @@ -4646,8 +4600,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &module, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { module = NULL; } @@ -4670,8 +4623,7 @@ if (res != 0) goto failed; asdl_seq_SET(names, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom"); return 1; @@ -4682,8 +4634,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &level, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { level = 0; } @@ -4717,8 +4668,7 @@ if (res != 0) goto failed; asdl_seq_SET(names, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global"); return 1; @@ -4753,8 +4703,7 @@ if (res != 0) goto failed; asdl_seq_SET(names, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal"); return 1; @@ -4776,8 +4725,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr"); return 1; @@ -4842,8 +4790,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &lineno, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr"); return 1; @@ -4854,8 +4801,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &col_offset, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr"); return 1; @@ -4874,8 +4820,7 @@ if (tmp == NULL) goto failed; res = obj2ast_boolop(tmp, &op, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp"); return 1; @@ -4899,8 +4844,7 @@ if (res != 0) goto failed; asdl_seq_SET(values, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp"); return 1; @@ -4924,8 +4868,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &left, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp"); return 1; @@ -4936,8 +4879,7 @@ if (tmp == NULL) goto failed; res = obj2ast_operator(tmp, &op, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp"); return 1; @@ -4948,8 +4890,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &right, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp"); return 1; @@ -4972,8 +4913,7 @@ if (tmp == NULL) goto failed; res = obj2ast_unaryop(tmp, &op, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp"); return 1; @@ -4984,8 +4924,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &operand, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp"); return 1; @@ -5008,8 +4947,7 @@ if (tmp == NULL) goto failed; res = obj2ast_arguments(tmp, &args, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda"); return 1; @@ -5020,8 +4958,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &body, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda"); return 1; @@ -5045,8 +4982,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &test, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp"); return 1; @@ -5057,8 +4993,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &body, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp"); return 1; @@ -5069,8 +5004,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &orelse, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp"); return 1; @@ -5106,8 +5040,7 @@ if (res != 0) goto failed; asdl_seq_SET(keys, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict"); return 1; @@ -5131,8 +5064,7 @@ if (res != 0) goto failed; asdl_seq_SET(values, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict"); return 1; @@ -5167,8 +5099,7 @@ if (res != 0) goto failed; asdl_seq_SET(elts, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set"); return 1; @@ -5191,8 +5122,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &elt, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp"); return 1; @@ -5216,8 +5146,7 @@ if (res != 0) goto failed; asdl_seq_SET(generators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp"); return 1; @@ -5240,8 +5169,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &elt, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp"); return 1; @@ -5265,8 +5193,7 @@ if (res != 0) goto failed; asdl_seq_SET(generators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp"); return 1; @@ -5290,8 +5217,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &key, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp"); return 1; @@ -5302,8 +5228,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp"); return 1; @@ -5327,8 +5252,7 @@ if (res != 0) goto failed; asdl_seq_SET(generators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp"); return 1; @@ -5351,8 +5275,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &elt, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp"); return 1; @@ -5376,8 +5299,7 @@ if (res != 0) goto failed; asdl_seq_SET(generators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp"); return 1; @@ -5399,8 +5321,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { value = NULL; } @@ -5421,8 +5342,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom"); return 1; @@ -5446,8 +5366,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &left, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare"); return 1; @@ -5471,8 +5390,7 @@ if (res != 0) goto failed; asdl_seq_SET(ops, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare"); return 1; @@ -5496,8 +5414,7 @@ if (res != 0) goto failed; asdl_seq_SET(comparators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare"); return 1; @@ -5523,8 +5440,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &func, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call"); return 1; @@ -5548,8 +5464,7 @@ if (res != 0) goto failed; asdl_seq_SET(args, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call"); return 1; @@ -5573,8 +5488,7 @@ if (res != 0) goto failed; asdl_seq_SET(keywords, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); return 1; @@ -5585,8 +5499,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &starargs, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { starargs = NULL; } @@ -5596,8 +5509,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &kwargs, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { kwargs = NULL; } @@ -5619,8 +5531,7 @@ if (tmp == NULL) goto failed; res = obj2ast_object(tmp, &n, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"n\" missing from Num"); return 1; @@ -5642,8 +5553,7 @@ if (tmp == NULL) goto failed; res = obj2ast_string(tmp, &s, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Str"); return 1; @@ -5665,8 +5575,7 @@ if (tmp == NULL) goto failed; res = obj2ast_bytes(tmp, &s, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Bytes"); return 1; @@ -5700,8 +5609,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute"); return 1; @@ -5712,8 +5620,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &attr, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute"); return 1; @@ -5724,8 +5631,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute"); return 1; @@ -5749,8 +5655,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript"); return 1; @@ -5761,8 +5666,7 @@ if (tmp == NULL) goto failed; res = obj2ast_slice(tmp, &slice, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript"); return 1; @@ -5773,8 +5677,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript"); return 1; @@ -5797,8 +5700,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred"); return 1; @@ -5809,8 +5711,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred"); return 1; @@ -5833,8 +5734,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &id, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name"); return 1; @@ -5845,8 +5745,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name"); return 1; @@ -5882,8 +5781,7 @@ if (res != 0) goto failed; asdl_seq_SET(elts, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List"); return 1; @@ -5894,8 +5792,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List"); return 1; @@ -5931,8 +5828,7 @@ if (res != 0) goto failed; asdl_seq_SET(elts, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple"); return 1; @@ -5943,8 +5839,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple"); return 1; @@ -6044,8 +5939,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &lower, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { lower = NULL; } @@ -6055,8 +5949,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &upper, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { upper = NULL; } @@ -6066,8 +5959,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &step, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { step = NULL; } @@ -6101,8 +5993,7 @@ if (res != 0) goto failed; asdl_seq_SET(dims, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"dims\" missing from ExtSlice"); return 1; @@ -6124,8 +6015,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Index"); return 1; @@ -6419,8 +6309,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &target, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension"); return 1; @@ -6431,8 +6320,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &iter, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension"); return 1; @@ -6456,8 +6344,7 @@ if (res != 0) goto failed; asdl_seq_SET(ifs, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension"); return 1; @@ -6488,8 +6375,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &lineno, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler"); return 1; @@ -6500,8 +6386,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &col_offset, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler"); return 1; @@ -6521,8 +6406,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &type, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { type = NULL; } @@ -6532,8 +6416,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &name, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { name = NULL; } @@ -6556,8 +6439,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler"); return 1; @@ -6605,8 +6487,7 @@ if (res != 0) goto failed; asdl_seq_SET(args, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments"); return 1; @@ -6617,8 +6498,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &vararg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { vararg = NULL; } @@ -6628,8 +6508,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &varargannotation, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { varargannotation = NULL; } @@ -6652,8 +6531,7 @@ if (res != 0) goto failed; asdl_seq_SET(kwonlyargs, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments"); return 1; @@ -6664,8 +6542,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &kwarg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { kwarg = NULL; } @@ -6675,8 +6552,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &kwargannotation, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { kwargannotation = NULL; } @@ -6699,8 +6575,7 @@ if (res != 0) goto failed; asdl_seq_SET(defaults, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments"); return 1; @@ -6724,8 +6599,7 @@ if (res != 0) goto failed; asdl_seq_SET(kw_defaults, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments"); return 1; @@ -6751,8 +6625,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &arg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg"); return 1; @@ -6763,8 +6636,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &annotation, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { annotation = NULL; } @@ -6788,8 +6660,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &arg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from keyword"); return 1; @@ -6800,8 +6671,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword"); return 1; @@ -6826,8 +6696,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &name, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias"); return 1; @@ -6838,8 +6707,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &asname, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { asname = NULL; } @@ -6863,8 +6731,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &context_expr, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem"); return 1; @@ -6875,8 +6742,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &optional_vars, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { optional_vars = NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 00:04:57 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 00:04:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogKE1lcmdlIDMuMykgUGFyc2VyL2FzZGxfYy5weTogdXNlIFB5X0NMRUFS?= =?utf-8?b?KCk=?= Message-ID: <3c248n0xSfz7Lk2@mail.python.org> http://hg.python.org/cpython/rev/9d26379db328 changeset: 84853:9d26379db328 parent: 84851:1b464f8453a4 parent: 84852:d14f40c87438 user: Victor Stinner date: Sat Jul 27 00:04:42 2013 +0200 summary: (Merge 3.3) Parser/asdl_c.py: use Py_CLEAR() files: Parser/asdl_c.py | 3 +- Python/Python-ast.c | 399 ++++++++++--------------------- 2 files changed, 134 insertions(+), 268 deletions(-) diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -535,8 +535,7 @@ (field.type, field.name), depth+1) self.emit("if (res != 0) goto failed;", depth+1) - self.emit("Py_XDECREF(tmp);", depth+1) - self.emit("tmp = NULL;", depth+1) + self.emit("Py_CLEAR(tmp);", depth+1) self.emit("} else {", depth) if not field.opt: message = "required field \\\"%s\\\" missing from %s" % (field.name, name) diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -3616,8 +3616,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module"); return 1; @@ -3652,8 +3651,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive"); return 1; @@ -3675,8 +3673,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &body, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression"); return 1; @@ -3711,8 +3708,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Suite"); return 1; @@ -3747,8 +3743,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &lineno, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt"); return 1; @@ -3759,8 +3754,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &col_offset, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt"); return 1; @@ -3782,8 +3776,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &name, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef"); return 1; @@ -3794,8 +3787,7 @@ if (tmp == NULL) goto failed; res = obj2ast_arguments(tmp, &args, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef"); return 1; @@ -3819,8 +3811,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef"); return 1; @@ -3844,8 +3835,7 @@ if (res != 0) goto failed; asdl_seq_SET(decorator_list, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef"); return 1; @@ -3856,8 +3846,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &returns, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { returns = NULL; } @@ -3885,8 +3874,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &name, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef"); return 1; @@ -3910,8 +3898,7 @@ if (res != 0) goto failed; asdl_seq_SET(bases, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef"); return 1; @@ -3935,8 +3922,7 @@ if (res != 0) goto failed; asdl_seq_SET(keywords, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); return 1; @@ -3947,8 +3933,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &starargs, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { starargs = NULL; } @@ -3958,8 +3943,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &kwargs, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { kwargs = NULL; } @@ -3982,8 +3966,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef"); return 1; @@ -4007,8 +3990,7 @@ if (res != 0) goto failed; asdl_seq_SET(decorator_list, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef"); return 1; @@ -4031,8 +4013,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { value = NULL; } @@ -4066,8 +4047,7 @@ if (res != 0) goto failed; asdl_seq_SET(targets, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete"); return 1; @@ -4103,8 +4083,7 @@ if (res != 0) goto failed; asdl_seq_SET(targets, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign"); return 1; @@ -4115,8 +4094,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign"); return 1; @@ -4140,8 +4118,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &target, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign"); return 1; @@ -4152,8 +4129,7 @@ if (tmp == NULL) goto failed; res = obj2ast_operator(tmp, &op, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign"); return 1; @@ -4164,8 +4140,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign"); return 1; @@ -4190,8 +4165,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &target, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For"); return 1; @@ -4202,8 +4176,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &iter, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For"); return 1; @@ -4227,8 +4200,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For"); return 1; @@ -4252,8 +4224,7 @@ if (res != 0) goto failed; asdl_seq_SET(orelse, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For"); return 1; @@ -4277,8 +4248,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &test, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While"); return 1; @@ -4302,8 +4272,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While"); return 1; @@ -4327,8 +4296,7 @@ if (res != 0) goto failed; asdl_seq_SET(orelse, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While"); return 1; @@ -4352,8 +4320,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &test, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If"); return 1; @@ -4377,8 +4344,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If"); return 1; @@ -4402,8 +4368,7 @@ if (res != 0) goto failed; asdl_seq_SET(orelse, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If"); return 1; @@ -4439,8 +4404,7 @@ if (res != 0) goto failed; asdl_seq_SET(items, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With"); return 1; @@ -4464,8 +4428,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With"); return 1; @@ -4488,8 +4451,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &exc, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { exc = NULL; } @@ -4499,8 +4461,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &cause, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { cause = NULL; } @@ -4537,8 +4498,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try"); return 1; @@ -4562,8 +4522,7 @@ if (res != 0) goto failed; asdl_seq_SET(handlers, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try"); return 1; @@ -4587,8 +4546,7 @@ if (res != 0) goto failed; asdl_seq_SET(orelse, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try"); return 1; @@ -4612,8 +4570,7 @@ if (res != 0) goto failed; asdl_seq_SET(finalbody, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try"); return 1; @@ -4637,8 +4594,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &test, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert"); return 1; @@ -4649,8 +4605,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &msg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { msg = NULL; } @@ -4684,8 +4639,7 @@ if (res != 0) goto failed; asdl_seq_SET(names, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import"); return 1; @@ -4709,8 +4663,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &module, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { module = NULL; } @@ -4733,8 +4686,7 @@ if (res != 0) goto failed; asdl_seq_SET(names, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom"); return 1; @@ -4745,8 +4697,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &level, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { level = 0; } @@ -4780,8 +4731,7 @@ if (res != 0) goto failed; asdl_seq_SET(names, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global"); return 1; @@ -4816,8 +4766,7 @@ if (res != 0) goto failed; asdl_seq_SET(names, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal"); return 1; @@ -4839,8 +4788,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr"); return 1; @@ -4905,8 +4853,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &lineno, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr"); return 1; @@ -4917,8 +4864,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &col_offset, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr"); return 1; @@ -4937,8 +4883,7 @@ if (tmp == NULL) goto failed; res = obj2ast_boolop(tmp, &op, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp"); return 1; @@ -4962,8 +4907,7 @@ if (res != 0) goto failed; asdl_seq_SET(values, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp"); return 1; @@ -4987,8 +4931,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &left, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp"); return 1; @@ -4999,8 +4942,7 @@ if (tmp == NULL) goto failed; res = obj2ast_operator(tmp, &op, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp"); return 1; @@ -5011,8 +4953,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &right, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp"); return 1; @@ -5035,8 +4976,7 @@ if (tmp == NULL) goto failed; res = obj2ast_unaryop(tmp, &op, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp"); return 1; @@ -5047,8 +4987,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &operand, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp"); return 1; @@ -5071,8 +5010,7 @@ if (tmp == NULL) goto failed; res = obj2ast_arguments(tmp, &args, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda"); return 1; @@ -5083,8 +5021,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &body, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda"); return 1; @@ -5108,8 +5045,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &test, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp"); return 1; @@ -5120,8 +5056,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &body, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp"); return 1; @@ -5132,8 +5067,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &orelse, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp"); return 1; @@ -5169,8 +5103,7 @@ if (res != 0) goto failed; asdl_seq_SET(keys, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict"); return 1; @@ -5194,8 +5127,7 @@ if (res != 0) goto failed; asdl_seq_SET(values, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict"); return 1; @@ -5230,8 +5162,7 @@ if (res != 0) goto failed; asdl_seq_SET(elts, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set"); return 1; @@ -5254,8 +5185,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &elt, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp"); return 1; @@ -5279,8 +5209,7 @@ if (res != 0) goto failed; asdl_seq_SET(generators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp"); return 1; @@ -5303,8 +5232,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &elt, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp"); return 1; @@ -5328,8 +5256,7 @@ if (res != 0) goto failed; asdl_seq_SET(generators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp"); return 1; @@ -5353,8 +5280,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &key, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp"); return 1; @@ -5365,8 +5291,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp"); return 1; @@ -5390,8 +5315,7 @@ if (res != 0) goto failed; asdl_seq_SET(generators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp"); return 1; @@ -5414,8 +5338,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &elt, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp"); return 1; @@ -5439,8 +5362,7 @@ if (res != 0) goto failed; asdl_seq_SET(generators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp"); return 1; @@ -5462,8 +5384,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { value = NULL; } @@ -5484,8 +5405,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom"); return 1; @@ -5509,8 +5429,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &left, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare"); return 1; @@ -5534,8 +5453,7 @@ if (res != 0) goto failed; asdl_seq_SET(ops, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare"); return 1; @@ -5559,8 +5477,7 @@ if (res != 0) goto failed; asdl_seq_SET(comparators, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare"); return 1; @@ -5586,8 +5503,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &func, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call"); return 1; @@ -5611,8 +5527,7 @@ if (res != 0) goto failed; asdl_seq_SET(args, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call"); return 1; @@ -5636,8 +5551,7 @@ if (res != 0) goto failed; asdl_seq_SET(keywords, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); return 1; @@ -5648,8 +5562,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &starargs, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { starargs = NULL; } @@ -5659,8 +5572,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &kwargs, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { kwargs = NULL; } @@ -5682,8 +5594,7 @@ if (tmp == NULL) goto failed; res = obj2ast_object(tmp, &n, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"n\" missing from Num"); return 1; @@ -5705,8 +5616,7 @@ if (tmp == NULL) goto failed; res = obj2ast_string(tmp, &s, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Str"); return 1; @@ -5728,8 +5638,7 @@ if (tmp == NULL) goto failed; res = obj2ast_bytes(tmp, &s, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Bytes"); return 1; @@ -5751,8 +5660,7 @@ if (tmp == NULL) goto failed; res = obj2ast_singleton(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from NameConstant"); return 1; @@ -5786,8 +5694,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute"); return 1; @@ -5798,8 +5705,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &attr, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute"); return 1; @@ -5810,8 +5716,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute"); return 1; @@ -5835,8 +5740,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript"); return 1; @@ -5847,8 +5751,7 @@ if (tmp == NULL) goto failed; res = obj2ast_slice(tmp, &slice, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript"); return 1; @@ -5859,8 +5762,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript"); return 1; @@ -5883,8 +5785,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred"); return 1; @@ -5895,8 +5796,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred"); return 1; @@ -5919,8 +5819,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &id, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name"); return 1; @@ -5931,8 +5830,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name"); return 1; @@ -5968,8 +5866,7 @@ if (res != 0) goto failed; asdl_seq_SET(elts, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List"); return 1; @@ -5980,8 +5877,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List"); return 1; @@ -6017,8 +5913,7 @@ if (res != 0) goto failed; asdl_seq_SET(elts, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple"); return 1; @@ -6029,8 +5924,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr_context(tmp, &ctx, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple"); return 1; @@ -6130,8 +6024,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &lower, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { lower = NULL; } @@ -6141,8 +6034,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &upper, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { upper = NULL; } @@ -6152,8 +6044,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &step, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { step = NULL; } @@ -6187,8 +6078,7 @@ if (res != 0) goto failed; asdl_seq_SET(dims, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"dims\" missing from ExtSlice"); return 1; @@ -6210,8 +6100,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Index"); return 1; @@ -6505,8 +6394,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &target, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension"); return 1; @@ -6517,8 +6405,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &iter, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension"); return 1; @@ -6542,8 +6429,7 @@ if (res != 0) goto failed; asdl_seq_SET(ifs, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension"); return 1; @@ -6574,8 +6460,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &lineno, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler"); return 1; @@ -6586,8 +6471,7 @@ if (tmp == NULL) goto failed; res = obj2ast_int(tmp, &col_offset, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler"); return 1; @@ -6607,8 +6491,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &type, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { type = NULL; } @@ -6618,8 +6501,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &name, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { name = NULL; } @@ -6642,8 +6524,7 @@ if (res != 0) goto failed; asdl_seq_SET(body, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler"); return 1; @@ -6689,8 +6570,7 @@ if (res != 0) goto failed; asdl_seq_SET(args, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments"); return 1; @@ -6701,8 +6581,7 @@ if (tmp == NULL) goto failed; res = obj2ast_arg(tmp, &vararg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { vararg = NULL; } @@ -6725,8 +6604,7 @@ if (res != 0) goto failed; asdl_seq_SET(kwonlyargs, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments"); return 1; @@ -6750,8 +6628,7 @@ if (res != 0) goto failed; asdl_seq_SET(kw_defaults, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments"); return 1; @@ -6762,8 +6639,7 @@ if (tmp == NULL) goto failed; res = obj2ast_arg(tmp, &kwarg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { kwarg = NULL; } @@ -6786,8 +6662,7 @@ if (res != 0) goto failed; asdl_seq_SET(defaults, i, value); } - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments"); return 1; @@ -6813,8 +6688,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &arg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg"); return 1; @@ -6825,8 +6699,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &annotation, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { annotation = NULL; } @@ -6850,8 +6723,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &arg, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from keyword"); return 1; @@ -6862,8 +6734,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &value, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword"); return 1; @@ -6888,8 +6759,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &name, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias"); return 1; @@ -6900,8 +6770,7 @@ if (tmp == NULL) goto failed; res = obj2ast_identifier(tmp, &asname, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { asname = NULL; } @@ -6925,8 +6794,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &context_expr, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem"); return 1; @@ -6937,8 +6805,7 @@ if (tmp == NULL) goto failed; res = obj2ast_expr(tmp, &optional_vars, arena); if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; + Py_CLEAR(tmp); } else { optional_vars = NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 00:21:56 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 27 Jul 2013 00:21:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NTM5?= =?utf-8?q?=3A__Calltips_now_work_for_float_default_arguments=2E?= Message-ID: <3c24XN3XHVz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/3236709650b0 changeset: 84854:3236709650b0 branch: 2.7 parent: 84823:a8d8bfb61874 user: Terry Jan Reedy date: Fri Jul 26 18:21:32 2013 -0400 summary: Issue #18539: Calltips now work for float default arguments. files: Lib/idlelib/CallTips.py | 2 +- Lib/idlelib/idle_test/test_calltips.py | 6 ++++++ Misc/NEWS | 2 ++ 3 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -163,7 +163,7 @@ if fob.func_code.co_flags & 0x8: items.append("***") arg_text = ", ".join(items) - arg_text = "(%s)" % re.sub("\.\d+", "", arg_text) + arg_text = "(%s)" % re.sub("(?", arg_text) # See if we can use the docstring doc = getattr(ob, "__doc__", "") if doc: diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -10,5 +10,11 @@ def test_good_entity(self): self.assertIs(CTi.get_entity('int'), int) +class Py2Test(unittest.TestCase): + def test_paramtuple_float(self): + # 18539: (a,b) becomes '.0' in code object; change that but not float + def f((a,b), c=0.0): pass + self.assertEqual(ct.get_arg_text(f), '(, c=0.0)') + if __name__ == '__main__': unittest.main(verbosity=2, exit=False) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -104,6 +104,8 @@ changed when it has not been changed. This fix followed the addition of a test file originally written by Phil Webster (the issue's main goal). +- Issue #18539: Calltips now work for float default arguments. + - Issue #7136: In the Idle File menu, "New Window" is renamed "New File". Patch by Tal Einat, Roget Serwy, and Todd Rovito. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 00:33:47 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 27 Jul 2013 00:33:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTUy?= =?utf-8?q?=3A_Check_return_value_of_PyArena=5FAddPyObject=28=29_in_obj2as?= =?utf-8?b?dF9vYmplY3QoKS4=?= Message-ID: <3c24p30LWxzSHm@mail.python.org> http://hg.python.org/cpython/rev/65121aa79ab3 changeset: 84855:65121aa79ab3 branch: 3.3 parent: 84852:d14f40c87438 user: Christian Heimes date: Sat Jul 27 00:33:13 2013 +0200 summary: Issue #18552: Check return value of PyArena_AddPyObject() in obj2ast_object(). files: Misc/NEWS | 3 +++ Parser/asdl_c.py | 10 +++++++--- Python/Python-ast.c | 10 +++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #18552: Check return value of PyArena_AddPyObject() in + obj2ast_object(). + - Issue #18560: Fix potential NULL pointer dereference in sum(). - Issue #15905: Fix theoretical buffer overflow in handling of sys.argv[0], diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -834,9 +834,13 @@ { if (obj == Py_None) obj = NULL; - if (obj) - PyArena_AddPyObject(arena, obj); - Py_XINCREF(obj); + if (obj) { + if (PyArena_AddPyObject(arena, obj) < 0) { + *out = NULL; + return -1; + } + Py_INCREF(obj); + } *out = obj; return 0; } diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -688,9 +688,13 @@ { if (obj == Py_None) obj = NULL; - if (obj) - PyArena_AddPyObject(arena, obj); - Py_XINCREF(obj); + if (obj) { + if (PyArena_AddPyObject(arena, obj) < 0) { + *out = NULL; + return -1; + } + Py_INCREF(obj); + } *out = obj; return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 00:33:48 2013 From: python-checkins at python.org (christian.heimes) Date: Sat, 27 Jul 2013 00:33:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318552=3A_Check_return_value_of_PyArena=5FAddPyO?= =?utf-8?q?bject=28=29_in_obj2ast=5Fobject=28=29=2E?= Message-ID: <3c24p42bXtz7LjV@mail.python.org> http://hg.python.org/cpython/rev/ad90fc28769a changeset: 84856:ad90fc28769a parent: 84853:9d26379db328 parent: 84855:65121aa79ab3 user: Christian Heimes date: Sat Jul 27 00:33:35 2013 +0200 summary: Issue #18552: Check return value of PyArena_AddPyObject() in obj2ast_object(). files: Misc/NEWS | 3 +++ Parser/asdl_c.py | 10 +++++++--- Python/Python-ast.c | 10 +++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18552: Check return value of PyArena_AddPyObject() in + obj2ast_object(). + - Issue #18560: Fix potential NULL pointer dereference in sum(). - Issue #18520: Add a new PyStructSequence_InitType2() function, same than diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -862,9 +862,13 @@ { if (obj == Py_None) obj = NULL; - if (obj) - PyArena_AddPyObject(arena, obj); - Py_XINCREF(obj); + if (obj) { + if (PyArena_AddPyObject(arena, obj) < 0) { + *out = NULL; + return -1; + } + Py_INCREF(obj); + } *out = obj; return 0; } diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -704,9 +704,13 @@ { if (obj == Py_None) obj = NULL; - if (obj) - PyArena_AddPyObject(arena, obj); - Py_XINCREF(obj); + if (obj) { + if (PyArena_AddPyObject(arena, obj) < 0) { + *out = NULL; + return -1; + } + Py_INCREF(obj); + } *out = obj; return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 01:06:02 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 01:06:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1ODkz?= =?utf-8?q?=3A_frozenmain=2Ec_now_handles_PyMem=5FMalloc=28=29_failure?= Message-ID: <3c25WG3rsbz7LjN@mail.python.org> http://hg.python.org/cpython/rev/ab8121466785 changeset: 84857:ab8121466785 branch: 3.3 parent: 84855:65121aa79ab3 user: Victor Stinner date: Sat Jul 27 01:04:56 2013 +0200 summary: Issue #15893: frozenmain.c now handles PyMem_Malloc() failure files: Modules/python.c | 16 ++++++++++------ Python/frozenmain.c | 11 +++++++++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Modules/python.c b/Modules/python.c --- a/Modules/python.c +++ b/Modules/python.c @@ -18,11 +18,19 @@ int main(int argc, char **argv) { - wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); + wchar_t **argv_copy; /* We need a second copy, as Python might modify the first one. */ - wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); + wchar_t **argv_copy2; int i, res; char *oldloc; + + argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); + argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + return 1; + } + /* 754 requires that FP exceptions run in "no stop" mode by default, * and until C vendors implement C99's ways to control FP exceptions, * Python requires non-stop mode. Alas, some platforms enable FP @@ -34,10 +42,6 @@ m = fpgetmask(); fpsetmask(m & ~FP_X_OFL); #endif - if (!argv_copy || !argv_copy2) { - fprintf(stderr, "out of memory\n"); - return 1; - } oldloc = strdup(setlocale(LC_ALL, NULL)); setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -20,9 +20,16 @@ int inspect = 0; int unbuffered = 0; char *oldloc; - wchar_t **argv_copy = PyMem_Malloc(sizeof(wchar_t*)*argc); + wchar_t **argv_copy; /* We need a second copies, as Python might modify the first one. */ - wchar_t **argv_copy2 = PyMem_Malloc(sizeof(wchar_t*)*argc); + wchar_t **argv_copy2; + + argv_copy = PyMem_Malloc(sizeof(wchar_t*)*argc); + argv_copy2 = PyMem_Malloc(sizeof(wchar_t*)*argc); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + return 1; + } Py_FrozenFlag = 1; /* Suppress errors from getpath.c */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 01:06:03 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 01:06:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_Issue_=2315893=3A_frozenmain=2Ec_now_h?= =?utf-8?q?andles_PyMem=5FMalloc=28=29_failure?= Message-ID: <3c25WH5lpxz7LjW@mail.python.org> http://hg.python.org/cpython/rev/386ab2c12301 changeset: 84858:386ab2c12301 parent: 84856:ad90fc28769a parent: 84857:ab8121466785 user: Victor Stinner date: Sat Jul 27 01:05:49 2013 +0200 summary: (Merge 3.3) Issue #15893: frozenmain.c now handles PyMem_Malloc() failure files: Python/frozenmain.c | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -20,9 +20,16 @@ int inspect = 0; int unbuffered = 0; char *oldloc; - wchar_t **argv_copy = PyMem_Malloc(sizeof(wchar_t*)*argc); + wchar_t **argv_copy; /* We need a second copies, as Python might modify the first one. */ - wchar_t **argv_copy2 = PyMem_Malloc(sizeof(wchar_t*)*argc); + wchar_t **argv_copy2; + + argv_copy = PyMem_Malloc(sizeof(wchar_t*)*argc); + argv_copy2 = PyMem_Malloc(sizeof(wchar_t*)*argc); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + return 1; + } Py_FrozenFlag = 1; /* Suppress errors from getpath.c */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 02:39:50 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 02:39:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318203=3A_Replace_?= =?utf-8?q?PyMem=5FMalloc=28=29_with_PyMem=5FRawMalloc=28=29_at_Python?= Message-ID: <3c27bV4Gy2z7LjM@mail.python.org> http://hg.python.org/cpython/rev/1cba6687993e changeset: 84859:1cba6687993e user: Victor Stinner date: Sat Jul 27 01:13:34 2013 +0200 summary: Issue #18203: Replace PyMem_Malloc() with PyMem_RawMalloc() at Python initialization files: Python/frozenmain.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -24,8 +24,8 @@ /* We need a second copies, as Python might modify the first one. */ wchar_t **argv_copy2; - argv_copy = PyMem_Malloc(sizeof(wchar_t*)*argc); - argv_copy2 = PyMem_Malloc(sizeof(wchar_t*)*argc); + argv_copy = PyMem_RawMalloc(sizeof(wchar_t*)*argc); + argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*)*argc); if (!argv_copy || !argv_copy2) { fprintf(stderr, "out of memory\n"); return 1; @@ -62,7 +62,7 @@ fprintf(stderr, "Could not convert argument %d to string\n", i); return 1; } - argv_copy[i] = PyMem_Malloc((argsize+1)*sizeof(wchar_t)); + argv_copy[i] = PyMem_RawMalloc((argsize+1)*sizeof(wchar_t)); argv_copy2[i] = argv_copy[i]; if (!argv_copy[i]) { fprintf(stderr, "out of memory\n"); @@ -109,9 +109,9 @@ #endif Py_Finalize(); for (i = 0; i < argc; i++) { - PyMem_Free(argv_copy2[i]); + PyMem_RawFree(argv_copy2[i]); } - PyMem_Free(argv_copy); - PyMem_Free(argv_copy2); + PyMem_RawFree(argv_copy); + PyMem_RawFree(argv_copy2); return sts; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 02:39:51 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 02:39:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Py=5FFrozenMain=28=29_now_?= =?utf-8?q?uses_=5FPy=5Fchar2wchar=28=29_to_decode_command_line_arguments?= =?utf-8?q?=2C_as?= Message-ID: <3c27bW6B3sz7LjY@mail.python.org> http://hg.python.org/cpython/rev/0001c4100823 changeset: 84860:0001c4100823 user: Victor Stinner date: Sat Jul 27 02:24:52 2013 +0200 summary: Py_FrozenMain() now uses _Py_char2wchar() to decode command line arguments, as done in main() files: Python/frozenmain.c | 22 ++++------------------ 1 files changed, 4 insertions(+), 18 deletions(-) diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -52,27 +52,13 @@ oldloc = setlocale(LC_ALL, NULL); setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { -#ifdef HAVE_BROKEN_MBSTOWCS - size_t argsize = strlen(argv[i]); -#else - size_t argsize = mbstowcs(NULL, argv[i], 0); -#endif - size_t count; - if (argsize == (size_t)-1) { - fprintf(stderr, "Could not convert argument %d to string\n", i); + argv_copy[i] = _Py_char2wchar(argv[i], NULL); + if (!argv_copy[i]) { + fprintf(stderr, "Unable to decode the command line argument #%i\n", + i + 1); return 1; } - argv_copy[i] = PyMem_RawMalloc((argsize+1)*sizeof(wchar_t)); argv_copy2[i] = argv_copy[i]; - if (!argv_copy[i]) { - fprintf(stderr, "out of memory\n"); - return 1; - } - count = mbstowcs(argv_copy[i], argv[i], argsize+1); - if (count == (size_t)-1) { - fprintf(stderr, "Could not convert argument %d to string\n", i); - return 1; - } } setlocale(LC_ALL, oldloc); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 02:39:53 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 02:39:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315893=3A_Improve_?= =?utf-8?q?error_handling_in_main=28=29_and_Py=5FFrozenMain=28=29?= Message-ID: <3c27bY0q9jz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/47c6aa17fd90 changeset: 84861:47c6aa17fd90 user: Victor Stinner date: Sat Jul 27 02:39:09 2013 +0200 summary: Issue #15893: Improve error handling in main() and Py_FrozenMain() * handle _PyMem_RawStrdup() failure * Py_FrozenMain() releases memory on error * Py_FrozenMain() duplicates the old locale, as done in main() files: Modules/python.c | 5 ++++ Python/frozenmain.c | 39 +++++++++++++++++++------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Modules/python.c b/Modules/python.c --- a/Modules/python.c +++ b/Modules/python.c @@ -45,6 +45,11 @@ #endif oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); + if (!oldloc) { + fprintf(stderr, "out of memory\n"); + return 1; + } + setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { argv_copy[i] = _Py_char2wchar(argv[i], NULL); diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -16,19 +16,19 @@ Py_FrozenMain(int argc, char **argv) { char *p; - int i, n, sts; + int i, n, sts = 1; int inspect = 0; int unbuffered = 0; - char *oldloc; - wchar_t **argv_copy; + char *oldloc = NULL; + wchar_t **argv_copy = NULL; /* We need a second copies, as Python might modify the first one. */ - wchar_t **argv_copy2; + wchar_t **argv_copy2 = NULL; - argv_copy = PyMem_RawMalloc(sizeof(wchar_t*)*argc); - argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*)*argc); + argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); if (!argv_copy || !argv_copy2) { fprintf(stderr, "out of memory\n"); - return 1; + goto error; } Py_FrozenFlag = 1; /* Suppress errors from getpath.c */ @@ -44,23 +44,26 @@ setbuf(stderr, (char *)NULL); } - if (!argv_copy) { + oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); + if (!oldloc) { fprintf(stderr, "out of memory\n"); - return 1; + goto error; } - oldloc = setlocale(LC_ALL, NULL); setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { argv_copy[i] = _Py_char2wchar(argv[i], NULL); + argv_copy2[i] = argv_copy[i]; if (!argv_copy[i]) { fprintf(stderr, "Unable to decode the command line argument #%i\n", i + 1); - return 1; + argc = i; + goto error; } - argv_copy2[i] = argv_copy[i]; } setlocale(LC_ALL, oldloc); + PyMem_RawFree(oldloc); + oldloc = NULL; #ifdef MS_WINDOWS PyInitFrozenExtensions(); @@ -94,10 +97,14 @@ PyWinFreeze_ExeTerm(); #endif Py_Finalize(); - for (i = 0; i < argc; i++) { - PyMem_RawFree(argv_copy2[i]); + +error: + PyMem_RawFree(argv_copy); + if (argv_copy2) { + for (i = 0; i < argc; i++) + PyMem_RawFree(argv_copy2[i]); + PyMem_RawFree(argv_copy2); } - PyMem_RawFree(argv_copy); - PyMem_RawFree(argv_copy2); + PyMem_RawFree(oldloc); return sts; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 02:42:08 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 02:42:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1ODkz?= =?utf-8?q?=3A_Remove_dead_code?= Message-ID: <3c27f83BKmzQGZ@mail.python.org> http://hg.python.org/cpython/rev/12af9db5212a changeset: 84862:12af9db5212a branch: 3.3 parent: 84857:ab8121466785 user: Victor Stinner date: Sat Jul 27 02:41:03 2013 +0200 summary: Issue #15893: Remove dead code files: Python/frozenmain.c | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -44,11 +44,6 @@ setbuf(stderr, (char *)NULL); } - if (!argv_copy) { - fprintf(stderr, "out of memory\n"); - return 1; - } - oldloc = setlocale(LC_ALL, NULL); setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 02:42:09 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 27 Jul 2013 02:42:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_null_merge_=28fix_already_applied_to_default=29?= Message-ID: <3c27f952Q5zQGZ@mail.python.org> http://hg.python.org/cpython/rev/e408e821d6c8 changeset: 84863:e408e821d6c8 parent: 84861:47c6aa17fd90 parent: 84862:12af9db5212a user: Victor Stinner date: Sat Jul 27 02:41:48 2013 +0200 summary: null merge (fix already applied to default) files: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jul 27 05:53:08 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 27 Jul 2013 05:53:08 +0200 Subject: [Python-checkins] Daily reference leaks (e408e821d6c8): sum=0 Message-ID: results for e408e821d6c8 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogwFbLbm', '-x'] From python-checkins at python.org Sat Jul 27 08:14:32 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 27 Jul 2013 08:14:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Assertions_key_off_NDEBUG?= Message-ID: <3c2H1h6wD9z7LjV@mail.python.org> http://hg.python.org/cpython/rev/35c88c53cf64 changeset: 84864:35c88c53cf64 user: Raymond Hettinger date: Fri Jul 26 23:14:22 2013 -0700 summary: Assertions key off NDEBUG files: Modules/_collectionsmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -61,7 +61,7 @@ * block is freed leaving another existing block as the new endpoint. */ -#ifdef Py_DEBUG +#ifndef NDEBUG #define MARK_END(link) link = NULL; #define CHECK_END(link) assert(link == NULL); #define CHECK_NOT_END(link) assert(link != NULL); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 21:54:27 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 27 Jul 2013 21:54:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Remove_repetit?= =?utf-8?q?ion_of_string_escapes_note_1_at_end_of_note_2=2E?= Message-ID: <3c2dCl2g4rzSyr@mail.python.org> http://hg.python.org/cpython/rev/c0788ee86a65 changeset: 84865:c0788ee86a65 branch: 2.7 parent: 84854:3236709650b0 user: Terry Jan Reedy date: Sat Jul 27 15:54:05 2013 -0400 summary: Remove repetition of string escapes note 1 at end of note 2. files: Doc/reference/lexical_analysis.rst | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -529,8 +529,7 @@ (2) Any Unicode character can be encoded this way, but characters outside the Basic Multilingual Plane (BMP) will be encoded using a surrogate pair if Python is - compiled to use 16-bit code units (the default). Individual code units which - form parts of a surrogate pair can be encoded using this escape sequence. + compiled to use 16-bit code units (the default). (3) As in Standard C, up to three octal digits are accepted. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 22:16:14 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 27 Jul 2013 22:16:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTcz?= =?utf-8?q?=3A_Complete_copy-paste_from_assertRaises_entry_to_assertWarns_?= =?utf-8?q?entry=2E?= Message-ID: <3c2dht1wW2z7LjZ@mail.python.org> http://hg.python.org/cpython/rev/55dcf9e065be changeset: 84866:55dcf9e065be branch: 3.3 parent: 84862:12af9db5212a user: Terry Jan Reedy date: Sat Jul 27 16:15:29 2013 -0400 summary: Issue #18573: Complete copy-paste from assertRaises entry to assertWarns entry. files: Doc/library/unittest.rst | 2 +- 1 files changed, 1 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 @@ -908,7 +908,7 @@ with self.assertWarns(SomeWarning): do_something() - When used as a context manager, :meth:`assertRaises` accepts the + When used as a context manager, :meth:`assertWarns` accepts the additional keyword argument *msg*. The context manager will store the caught warning object in its -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 22:16:15 2013 From: python-checkins at python.org (terry.reedy) Date: Sat, 27 Jul 2013 22:16:15 +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: <3c2dhv3vCqz7LkC@mail.python.org> http://hg.python.org/cpython/rev/852e824c7093 changeset: 84867:852e824c7093 parent: 84864:35c88c53cf64 parent: 84866:55dcf9e065be user: Terry Jan Reedy date: Sat Jul 27 16:15:51 2013 -0400 summary: Merge with 3.3 files: Doc/library/unittest.rst | 2 +- 1 files changed, 1 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 @@ -985,7 +985,7 @@ with self.assertWarns(SomeWarning): do_something() - When used as a context manager, :meth:`assertRaises` accepts the + When used as a context manager, :meth:`assertWarns` accepts the additional keyword argument *msg*. The context manager will store the caught warning object in its -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 23:07:39 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 27 Jul 2013 23:07:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_add_a_test_for?= =?utf-8?q?_issue_=2317669_=28closes_=2318565=29?= Message-ID: <3c2frC0hPgz7LjS@mail.python.org> http://hg.python.org/cpython/rev/516303f32bad changeset: 84868:516303f32bad branch: 3.3 parent: 84866:55dcf9e065be user: Benjamin Peterson date: Sat Jul 27 14:06:56 2013 -0700 summary: add a test for issue #17669 (closes #18565) Patch from Phil Connell. files: Lib/test/test_pep380.py | 41 ++++++++++++++++++++++++++++- 1 files changed, 40 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pep380.py b/Lib/test/test_pep380.py --- a/Lib/test/test_pep380.py +++ b/Lib/test/test_pep380.py @@ -13,7 +13,7 @@ import inspect import parser -from test.support import captured_stderr +from test.support import captured_stderr, disable_gc, gc_collect class TestPEP380Operation(unittest.TestCase): """ @@ -954,6 +954,45 @@ list(gen()) self.assertEqual(ret, 42) + def test_close_with_cleared_frame(self): + # See issue #17669. + # + # Create a stack of generators: outer() delegating to inner() + # delegating to innermost(). The key point is that the instance of + # inner is created first: this ensures that its frame appears before + # the instance of outer in the GC linked list. + # + # At the gc.collect call: + # - frame_clear is called on the inner_gen frame. + # - gen_dealloc is called on the outer_gen generator (the only + # reference is in the frame's locals). + # - gen_close is called on the outer_gen generator. + # - gen_close_iter is called to close the inner_gen generator, which + # in turn calls gen_close, and gen_yf. + # + # Previously, gen_yf would crash since inner_gen's frame had been + # cleared (and in particular f_stacktop was NULL). + + def innermost(): + yield + def inner(): + outer_gen = yield + yield from innermost() + def outer(): + inner_gen = yield + yield from inner_gen + + with disable_gc(): + inner_gen = inner() + outer_gen = outer() + outer_gen.send(None) + outer_gen.send(inner_gen) + outer_gen.send(outer_gen) + + del outer_gen + del inner_gen + gc_collect() + def test_main(): from test import support -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 27 23:07:40 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 27 Jul 2013 23:07:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMTg1NjUp?= Message-ID: <3c2frD2X9mz7LjX@mail.python.org> http://hg.python.org/cpython/rev/f90e7540dcba changeset: 84869:f90e7540dcba parent: 84867:852e824c7093 parent: 84868:516303f32bad user: Benjamin Peterson date: Sat Jul 27 14:07:19 2013 -0700 summary: merge 3.3 (#18565) files: Lib/test/test_pep380.py | 41 ++++++++++++++++++++++++++++- 1 files changed, 40 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pep380.py b/Lib/test/test_pep380.py --- a/Lib/test/test_pep380.py +++ b/Lib/test/test_pep380.py @@ -13,7 +13,7 @@ import inspect import parser -from test.support import captured_stderr +from test.support import captured_stderr, disable_gc, gc_collect class TestPEP380Operation(unittest.TestCase): """ @@ -954,6 +954,45 @@ list(gen()) self.assertEqual(ret, 42) + def test_close_with_cleared_frame(self): + # See issue #17669. + # + # Create a stack of generators: outer() delegating to inner() + # delegating to innermost(). The key point is that the instance of + # inner is created first: this ensures that its frame appears before + # the instance of outer in the GC linked list. + # + # At the gc.collect call: + # - frame_clear is called on the inner_gen frame. + # - gen_dealloc is called on the outer_gen generator (the only + # reference is in the frame's locals). + # - gen_close is called on the outer_gen generator. + # - gen_close_iter is called to close the inner_gen generator, which + # in turn calls gen_close, and gen_yf. + # + # Previously, gen_yf would crash since inner_gen's frame had been + # cleared (and in particular f_stacktop was NULL). + + def innermost(): + yield + def inner(): + outer_gen = yield + yield from innermost() + def outer(): + inner_gen = yield + yield from inner_gen + + with disable_gc(): + inner_gen = inner() + outer_gen = outer() + outer_gen.send(None) + outer_gen.send(inner_gen) + outer_gen.send(outer_gen) + + del outer_gen + del inner_gen + gc_collect() + def test_main(): from test import support -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 01:09:43 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 01:09:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_Make_test=2Esupport=2Erequires=28=27gui=27=29_skip_when_it_?= =?utf-8?q?should=2E?= Message-ID: <3c2jY31SQ0z7LjW@mail.python.org> http://hg.python.org/cpython/rev/dd9941f5fcda changeset: 84870:dd9941f5fcda branch: 2.7 parent: 84865:c0788ee86a65 user: Terry Jan Reedy date: Sun Jul 21 20:13:24 2013 -0400 summary: Issue #18441: Make test.support.requires('gui') skip when it should. (Consolidating this check and various checks in tkinter files and moving them to test.support and test.regrtest will be another issue.) files: Lib/idlelib/idle_test/test_text.py | 5 +--- Lib/test/test_idle.py | 20 ++++++++++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -216,10 +216,7 @@ requires('gui') from Tkinter import Tk, Text cls.Text = Text - try: - cls.root = Tk() - except TclError as msg: - raise unittest.SkipTest('TclError: %s' % msg) + cls.root = Tk() @classmethod def tearDownClass(cls): 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,9 +1,21 @@ -# Skip test if _tkinter or _thread wasn't built or idlelib was deleted. -from test.test_support import import_module -import_module('Tkinter') -import_module('threading') # imported by PyShell, imports _thread +# Skip test if _thread or _tkinter wasn't built or idlelib was deleted. +from test.test_support import import_module, use_resources +import_module('threading') # imported by idlelib.PyShell, imports _thread +tk = import_module('Tkinter') idletest = import_module('idlelib.idle_test') +# If buildbot improperly sets gui resource (#18365, #18441), remove it +# so requires('gui') tests are skipped while non-gui tests still run. +if use_resources and 'gui' in use_resources: + try: + root = tk.Tk() + root.destroy() + except TclError: + while True: + use_resources.delete('gui') + if 'gui' not in use_resources: + break + # 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.) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 01:09:44 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 01:09:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_Correct_previous_patch=2C_which_hg_committed_before_I_wante?= =?utf-8?q?d_it_to=2E?= Message-ID: <3c2jY43K6gz7LjX@mail.python.org> http://hg.python.org/cpython/rev/d9a53ab464ea changeset: 84871:d9a53ab464ea branch: 2.7 user: Terry Jan Reedy date: Sat Jul 27 19:07:07 2013 -0400 summary: Issue #18441: Correct previous patch, which hg committed before I wanted it to. files: Lib/test/test_idle.py | 10 ++++------ 1 files changed, 4 insertions(+), 6 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,4 +1,5 @@ # Skip test if _thread or _tkinter wasn't built or idlelib was deleted. +from test import test_support as support from test.test_support import import_module, use_resources import_module('threading') # imported by idlelib.PyShell, imports _thread tk = import_module('Tkinter') @@ -10,11 +11,9 @@ try: root = tk.Tk() root.destroy() - except TclError: - while True: - use_resources.delete('gui') - if 'gui' not in use_resources: - break + except tk.TclError: + while 'gui' in use_resources: + use_resources.remove('gui') # Without test_main present, regrtest.runtest_inner (line1219) calls # unittest.TestLoader().loadTestsFromModule(this_module) which calls @@ -25,7 +24,6 @@ # Until unittest supports resources, we emulate regrtest's -ugui # so loaded tests run the same as if textually present here. # If any Idle test ever needs another resource, add it to the list. - from test import support support.use_resources = ['gui'] # use_resources is initially None import unittest unittest.main(verbosity=2, exit=False) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 02:29:15 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 02:29:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Update_int_div?= =?utf-8?q?ision_to_quiet_2to3_warning=2E?= Message-ID: <3c2lJq6V1xzRZS@mail.python.org> http://hg.python.org/cpython/rev/38d47ac7fc2d changeset: 84872:38d47ac7fc2d branch: 2.7 user: Terry Jan Reedy date: Sat Jul 27 20:28:53 2013 -0400 summary: Update int division to quiet 2to3 warning. files: Lib/lib-tk/test/test_ttk/test_widgets.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/lib-tk/test/test_ttk/test_widgets.py b/Lib/lib-tk/test/test_ttk/test_widgets.py --- a/Lib/lib-tk/test/test_ttk/test_widgets.py +++ b/Lib/lib-tk/test/test_ttk/test_widgets.py @@ -26,8 +26,8 @@ def test_identify(self): self.widget.update_idletasks() self.assertEqual(self.widget.identify( - int(self.widget.winfo_width() / 2), - int(self.widget.winfo_height() / 2) + self.widget.winfo_width() // 2, + self.widget.winfo_height() // 2 ), "label") self.assertEqual(self.widget.identify(-1, -1), "") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 02:57:19 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 28 Jul 2013 02:57:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_doc_of_PYTHONF?= =?utf-8?q?AULTHANDLER_env_var=3A_add_missing_=22versionadded=22_tag?= Message-ID: <3c2lxC3TBzz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/d0b129c587f5 changeset: 84873:d0b129c587f5 branch: 3.3 parent: 84868:516303f32bad user: Victor Stinner date: Sun Jul 28 02:56:50 2013 +0200 summary: doc of PYTHONFAULTHANDLER env var: add missing "versionadded" tag files: Doc/using/cmdline.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -562,6 +562,8 @@ Python traceback. This is equivalent to :option:`-X` ``faulthandler`` option. + .. versionadded:: 3.3 + Debug-mode variables ~~~~~~~~~~~~~~~~~~~~ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 02:57:20 2013 From: python-checkins at python.org (victor.stinner) Date: Sun, 28 Jul 2013 02:57:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_doc_of_PYTHONFAULTHANDLER_env_var=3A_a?= =?utf-8?q?dd_missing_=22versionadded=22_tag?= Message-ID: <3c2lxD5NBPz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/66a3dc613627 changeset: 84874:66a3dc613627 parent: 84869:f90e7540dcba parent: 84873:d0b129c587f5 user: Victor Stinner date: Sun Jul 28 02:57:02 2013 +0200 summary: (Merge 3.3) doc of PYTHONFAULTHANDLER env var: add missing "versionadded" tag files: Doc/using/cmdline.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -575,6 +575,8 @@ Python traceback. This is equivalent to :option:`-X` ``faulthandler`` option. + .. versionadded:: 3.3 + Debug-mode variables ~~~~~~~~~~~~~~~~~~~~ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 04:29:35 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 04:29:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_add_Mac_=28darwin=29_gui_check=2E_This_is_not_needed_today?= =?utf-8?q?=2C_but_has_been?= Message-ID: <3c2nzg2c5Pz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/9a4c62c1a4c0 changeset: 84875:9a4c62c1a4c0 branch: 2.7 parent: 84872:38d47ac7fc2d user: Terry Jan Reedy date: Sat Jul 27 22:06:03 2013 -0400 summary: Issue #18441: add Mac (darwin) gui check. This is not needed today, but has been in the past and might be needed again in the future files: Lib/test/test_idle.py | 15 ++++++++++++--- 1 files changed, 12 insertions(+), 3 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,14 +1,24 @@ -# Skip test if _thread or _tkinter wasn't built or idlelib was deleted. +import unittest from test import test_support as support from test.test_support import import_module, use_resources + +# Skip test if _thread or _tkinter wasn't built or idlelib was deleted. import_module('threading') # imported by idlelib.PyShell, imports _thread -tk = import_module('Tkinter') +tk = import_module('Tkinter') # imports _tkinter idletest = import_module('idlelib.idle_test') # If buildbot improperly sets gui resource (#18365, #18441), remove it # so requires('gui') tests are skipped while non-gui tests still run. if use_resources and 'gui' in use_resources: try: + import sys + if sys.platform == 'darwin': + from lib-tk.test.runtktests import check_tk_availability + # tkinter.test.suppport in 3.x + try: + check_tk_availability() + except unittest.SkipTest: + raise tk.TclError root = tk.Tk() root.destroy() except tk.TclError: @@ -25,5 +35,4 @@ # so loaded tests run the same as if textually present here. # If any Idle test ever needs another resource, add it to the list. support.use_resources = ['gui'] # use_resources is initially None - import unittest unittest.main(verbosity=2, exit=False) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 04:29:36 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 04:29:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_Comment_out_code_that_will_not_compile_because_the_standard?= Message-ID: <3c2nzh4RvRz7Lk9@mail.python.org> http://hg.python.org/cpython/rev/ba5c264d67ea changeset: 84876:ba5c264d67ea branch: 2.7 user: Terry Jan Reedy date: Sat Jul 27 22:27:25 2013 -0400 summary: Issue #18441: Comment out code that will not compile because the standard library has a package, lib-tk, that cannot be imported by normal means. Lib/test/test_tk, etc, have special code to access this package. I will not bother with it unless the darwin check is needed before it gets moved to test.(test-)support.py. files: Lib/test/test_idle.py | 15 ++++++++------- 1 files changed, 8 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 @@ -12,13 +12,14 @@ if use_resources and 'gui' in use_resources: try: import sys - if sys.platform == 'darwin': - from lib-tk.test.runtktests import check_tk_availability - # tkinter.test.suppport in 3.x - try: - check_tk_availability() - except unittest.SkipTest: - raise tk.TclError +## if sys.platform == 'darwin': +## from lib-tk.test.runtktests import check_tk_availability +# see test/test_tk.py or test_ttk_guionly for how to import the above +## # tkinter.test.suppport in 3.x +## try: +## check_tk_availability() +## except unittest.SkipTest: +## raise tk.TclError root = tk.Tk() root.destroy() except tk.TclError: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 04:29:37 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 04:29:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_whitespace?= Message-ID: <3c2nzj6KPfz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/6420dcd377f9 changeset: 84877:6420dcd377f9 branch: 2.7 user: Terry Jan Reedy date: Sat Jul 27 22:29:09 2013 -0400 summary: Issue #18441: whitespace files: Lib/test/test_idle.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -18,7 +18,7 @@ ## # tkinter.test.suppport in 3.x ## try: ## check_tk_availability() -## except unittest.SkipTest: +## except unittest.SkipTest: ## raise tk.TclError root = tk.Tk() root.destroy() -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 28 05:53:23 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 28 Jul 2013 05:53:23 +0200 Subject: [Python-checkins] Daily reference leaks (66a3dc613627): sum=2 Message-ID: results for 66a3dc613627 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/reflogCy56ix', '-x'] From python-checkins at python.org Sun Jul 28 06:01:25 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 06:01:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_Make_test=2Esupport=2Erequires=28=27gui=27=29_skip_when_it_?= =?utf-8?q?should=2E?= Message-ID: <3c2r1d2FhxzSN6@mail.python.org> http://hg.python.org/cpython/rev/c3936a52f215 changeset: 84878:c3936a52f215 branch: 3.3 parent: 84873:d0b129c587f5 user: Terry Jan Reedy date: Sun Jul 28 00:00:20 2013 -0400 summary: Issue #18441: Make test.support.requires('gui') skip when it should. files: Lib/test/test_idle.py | 22 +++++++++++++++++----- 1 files changed, 17 insertions(+), 5 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,9 +1,23 @@ -# Skip test if _tkinter or _thread wasn't built or idlelib was deleted. -from test.support import import_module -import_module('tkinter') +import unittest +from test import support +from test.support import import_module, use_resources + +# Skip test if _thread or _tkinter wasn't built or idlelib was deleted. import_module('threading') # imported by PyShell, imports _thread +tk = import_module('tkinter') # imports _tkinter idletest = import_module('idlelib.idle_test') +# If buildbot improperly sets gui resource (#18365, #18441), remove it +# so requires('gui') tests are skipped while non-gui tests still run. +# If there is a problem with Macs, see #18441, msg 193805 +if use_resources and 'gui' in use_resources: + try: + root = tk.Tk() + root.destroy() + except tk.TclError: + while 'gui' in use_resources: + use_resources.remove('gui') + # 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.) @@ -13,7 +27,5 @@ # Until unittest supports resources, we emulate regrtest's -ugui # so loaded tests run the same as if textually present here. # If any Idle test ever needs another resource, add it to the list. - from test import support support.use_resources = ['gui'] # use_resources is initially None - import unittest unittest.main(verbosity=2, exit=False) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 06:01:26 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 06:01:26 +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: <3c2r1f4C9Hz7LkT@mail.python.org> http://hg.python.org/cpython/rev/a6cac0aff498 changeset: 84879:a6cac0aff498 parent: 84874:66a3dc613627 parent: 84878:c3936a52f215 user: Terry Jan Reedy date: Sun Jul 28 00:00:47 2013 -0400 summary: Merge with 3.3 files: Lib/test/test_idle.py | 22 +++++++++++++++++----- 1 files changed, 17 insertions(+), 5 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,9 +1,23 @@ -# Skip test if _tkinter or _thread wasn't built or idlelib was deleted. -from test.support import import_module -import_module('tkinter') +import unittest +from test import support +from test.support import import_module, use_resources + +# Skip test if _thread or _tkinter wasn't built or idlelib was deleted. import_module('threading') # imported by PyShell, imports _thread +tk = import_module('tkinter') # imports _tkinter idletest = import_module('idlelib.idle_test') +# If buildbot improperly sets gui resource (#18365, #18441), remove it +# so requires('gui') tests are skipped while non-gui tests still run. +# If there is a problem with Macs, see #18441, msg 193805 +if use_resources and 'gui' in use_resources: + try: + root = tk.Tk() + root.destroy() + except tk.TclError: + while 'gui' in use_resources: + use_resources.remove('gui') + # 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.) @@ -13,7 +27,5 @@ # Until unittest supports resources, we emulate regrtest's -ugui # so loaded tests run the same as if textually present here. # If any Idle test ever needs another resource, add it to the list. - from test import support support.use_resources = ['gui'] # use_resources is initially None - import unittest unittest.main(verbosity=2, exit=False) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 06:01:27 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 06:01:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_Move_commented_out_code_to_issue_message=2E?= Message-ID: <3c2r1g63v9z7LkT@mail.python.org> http://hg.python.org/cpython/rev/858a72d91162 changeset: 84880:858a72d91162 branch: 2.7 parent: 84877:6420dcd377f9 user: Terry Jan Reedy date: Sun Jul 28 00:01:00 2013 -0400 summary: Issue #18441: Move commented out code to issue message. files: Lib/test/test_idle.py | 10 +--------- 1 files changed, 1 insertions(+), 9 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 @@ -9,17 +9,9 @@ # If buildbot improperly sets gui resource (#18365, #18441), remove it # so requires('gui') tests are skipped while non-gui tests still run. +# If there is a problem with Macs, see #18441, msg 193805 if use_resources and 'gui' in use_resources: try: - import sys -## if sys.platform == 'darwin': -## from lib-tk.test.runtktests import check_tk_availability -# see test/test_tk.py or test_ttk_guionly for how to import the above -## # tkinter.test.suppport in 3.x -## try: -## check_tk_availability() -## except unittest.SkipTest: -## raise tk.TclError root = tk.Tk() root.destroy() except tk.TclError: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 11:34:50 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 28 Jul 2013 11:34:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Restore_the_da?= =?utf-8?q?ta_block_size_to_62=2E?= Message-ID: <3c2zQL3K6Nz7LkT@mail.python.org> http://hg.python.org/cpython/rev/2f5ee102f083 changeset: 84881:2f5ee102f083 branch: 2.7 user: Raymond Hettinger date: Sun Jul 28 02:34:42 2013 -0700 summary: Restore the data block size to 62. The former block size traded away good fit within cache lines in order to gain faster division in deque_item(). However, compilers are getting smarter and can now replace the slow division operation with a fast integer multiply and right shift. Accordingly, it makes sense to go back to a size that lets blocks neatly fill entire cache-lines. GCC-4.8 and CLANG 4.0 both compute "x // 62" with something roughly equivalent to "x * 9520900167075897609 >> 69". files: Lib/test/test_deque.py | 2 +- Modules/_collectionsmodule.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -522,7 +522,7 @@ @test_support.cpython_only def test_sizeof(self): - BLOCKLEN = 64 + BLOCKLEN = 62 basesize = test_support.calcobjsize('2P4PlP') blocksize = struct.calcsize('2P%dP' % BLOCKLEN) self.assertEqual(object.__sizeof__(deque()), basesize) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -10,11 +10,14 @@ /* The block length may be set to any number over 1. Larger numbers * reduce the number of calls to the memory allocator, give faster * indexing and rotation, and reduce the link::data overhead ratio. - * Ideally, the block length should be a power-of-two for faster - * division/modulo computations during indexing. + * + * Ideally, the block length will be set to two less than some + * multiple of the cache-line length (so that the full block + * including the leftlink and rightlink will fit neatly into + * cache lines). */ -#define BLOCKLEN 64 +#define BLOCKLEN 62 #define CENTER ((BLOCKLEN - 1) / 2) /* A `dequeobject` is composed of a doubly-linked list of `block` nodes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 11:40:20 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 28 Jul 2013 11:40:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Restore_the_data_block_siz?= =?utf-8?q?e_to_62=2E?= Message-ID: <3c2zXh5vXPz7Lkj@mail.python.org> http://hg.python.org/cpython/rev/947e117049fb changeset: 84882:947e117049fb parent: 84879:a6cac0aff498 user: Raymond Hettinger date: Sun Jul 28 02:39:49 2013 -0700 summary: Restore the data block size to 62. The former block size traded away good fit within cache lines in order to gain faster division in deque_item(). However, compilers are getting smarter and can now replace the slow division operation with a fast integer multiply and right shift. Accordingly, it makes sense to go back to a size that lets blocks neatly fill entire cache-lines. GCC-4.8 and CLANG 4.0 both compute "x // 62" with something roughly equivalent to "x * 9520900167075897609 >> 69". files: Lib/test/test_deque.py | 2 +- Modules/_collectionsmodule.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -536,7 +536,7 @@ @support.cpython_only def test_sizeof(self): - BLOCKLEN = 64 + BLOCKLEN = 62 basesize = support.calcobjsize('2P4nlP') blocksize = struct.calcsize('2P%dP' % BLOCKLEN) self.assertEqual(object.__sizeof__(deque()), basesize) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -10,11 +10,14 @@ /* The block length may be set to any number over 1. Larger numbers * reduce the number of calls to the memory allocator, give faster * indexing and rotation, and reduce the link::data overhead ratio. - * If the block length is a power-of-two, we also get faster - * division/modulo computations during indexing. + * + * Ideally, the block length will be set to two less than some + * multiple of the cache-line length (so that the full block + * including the leftlink and rightlink will fit neatly into + * cache lines). */ -#define BLOCKLEN 64 +#define BLOCKLEN 62 #define CENTER ((BLOCKLEN - 1) / 2) /* A `dequeobject` is composed of a doubly-linked list of `block` nodes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 12:00:31 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 28 Jul 2013 12:00:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2313266=3A_Add_insp?= =?utf-8?q?ect=2Eunwrap?= Message-ID: <3c2zzz2TFTz7Llk@mail.python.org> http://hg.python.org/cpython/rev/2aa6c1e35b8a changeset: 84883:2aa6c1e35b8a user: Nick Coghlan date: Sun Jul 28 20:00:01 2013 +1000 summary: Close #13266: Add inspect.unwrap Initial patch by Daniel Urban and Aaron Iles files: Doc/library/inspect.rst | 17 ++++++ Doc/whatsnew/3.4.rst | 14 ++++- Lib/inspect.py | 44 ++++++++++++++-- Lib/test/test_inspect.py | 74 +++++++++++++++++++++++++++- Misc/NEWS | 3 + 5 files changed, 141 insertions(+), 11 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -797,6 +797,23 @@ .. versionadded:: 3.3 +.. function:: unwrap(func, *, stop=None) + + Get the object wrapped by *func*. It follows the chain of :attr:`__wrapped__` + attributes returning the last object in the chain. + + *stop* is an optional callback accepting an object in the wrapper chain + as its sole argument that allows the unwrapping to be terminated early if + the callback returns a true value. If the callback never returns a true + value, the last object in the chain is returned as usual. For example, + :func:`signature` uses this to stop unwrapping if any object in the + chain has a ``__signature__`` attribute defined. + + :exc:`ValueError` is raised if a cycle is encountered. + + .. versionadded:: 3.4 + + .. _inspect-stack: The interpreter stack 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 @@ -185,6 +185,15 @@ New :func:`functools.singledispatch` decorator: see the :pep:`443`. + +inspect +------- + +:func:`~inspect.unwrap` makes it easy to unravel wrapper function chains +created by :func:`functools.wraps` (and any other API that sets the +``__wrapped__`` attribute on a wrapper function). + + smtplib ------- @@ -327,6 +336,5 @@ wrapped attribute set. This means ``__wrapped__`` attributes now correctly link a stack of decorated functions rather than every ``__wrapped__`` attribute in the chain referring to the innermost function. Introspection - libraries that assumed the previous behaviour was intentional will need to - be updated to walk the chain of ``__wrapped__`` attributes to find the - innermost function. + libraries that assumed the previous behaviour was intentional can use + :func:`inspect.unwrap` to gain equivalent behaviour. diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -360,6 +360,40 @@ "Return tuple of base classes (including cls) in method resolution order." return cls.__mro__ +# -------------------------------------------------------- function helpers + +def unwrap(func, *, stop=None): + """Get the object wrapped by *func*. + + Follows the chain of :attr:`__wrapped__` attributes returning the last + object in the chain. + + *stop* is an optional callback accepting an object in the wrapper chain + as its sole argument that allows the unwrapping to be terminated early if + the callback returns a true value. If the callback never returns a true + value, the last object in the chain is returned as usual. For example, + :func:`signature` uses this to stop unwrapping if any object in the + chain has a ``__signature__`` attribute defined. + + :exc:`ValueError` is raised if a cycle is encountered. + + """ + if stop is None: + def _is_wrapper(f): + return hasattr(f, '__wrapped__') + else: + def _is_wrapper(f): + return hasattr(f, '__wrapped__') and not stop(f) + f = func # remember the original func for error reporting + memo = {id(f)} # Memoise by id to tolerate non-hashable objects + while _is_wrapper(func): + func = func.__wrapped__ + id_func = id(func) + if id_func in memo: + raise ValueError('wrapper loop when unwrapping {!r}'.format(f)) + memo.add(id_func) + return func + # -------------------------------------------------- source code extraction def indentsize(line): """Return the indent size, in spaces, at the start of a line of text.""" @@ -1346,6 +1380,9 @@ sig = signature(obj.__func__) return sig.replace(parameters=tuple(sig.parameters.values())[1:]) + # Was this function wrapped by a decorator? + obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__"))) + try: sig = obj.__signature__ except AttributeError: @@ -1354,13 +1391,6 @@ if sig is not None: return sig - try: - # Was this function wrapped by a decorator? - wrapped = obj.__wrapped__ - except AttributeError: - pass - else: - return signature(wrapped) if isinstance(obj, types.FunctionType): return Signature.from_function(obj) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -8,6 +8,7 @@ import collections import os import shutil +import functools from os.path import normcase from test.support import run_unittest, TESTFN, DirsOnSysPath @@ -1719,6 +1720,17 @@ ((('b', ..., ..., "positional_or_keyword"),), ...)) + # Test we handle __signature__ partway down the wrapper stack + def wrapped_foo_call(): + pass + wrapped_foo_call.__wrapped__ = Foo.__call__ + + self.assertEqual(self.signature(wrapped_foo_call), + ((('a', ..., ..., "positional_or_keyword"), + ('b', ..., ..., "positional_or_keyword")), + ...)) + + def test_signature_on_class(self): class C: def __init__(self, a): @@ -1833,6 +1845,10 @@ self.assertEqual(self.signature(Wrapped), ((('a', ..., ..., "positional_or_keyword"),), ...)) + # wrapper loop: + Wrapped.__wrapped__ = Wrapped + with self.assertRaisesRegex(ValueError, 'wrapper loop'): + self.signature(Wrapped) def test_signature_on_lambdas(self): self.assertEqual(self.signature((lambda a=10: a)), @@ -2284,6 +2300,62 @@ self.assertNotEqual(ba, ba4) +class TestUnwrap(unittest.TestCase): + + def test_unwrap_one(self): + def func(a, b): + return a + b + wrapper = functools.lru_cache(maxsize=20)(func) + self.assertIs(inspect.unwrap(wrapper), func) + + def test_unwrap_several(self): + def func(a, b): + return a + b + wrapper = func + for __ in range(10): + @functools.wraps(wrapper) + def wrapper(): + pass + self.assertIsNot(wrapper.__wrapped__, func) + self.assertIs(inspect.unwrap(wrapper), func) + + def test_stop(self): + def func1(a, b): + return a + b + @functools.wraps(func1) + def func2(): + pass + @functools.wraps(func2) + def wrapper(): + pass + func2.stop_here = 1 + unwrapped = inspect.unwrap(wrapper, + stop=(lambda f: hasattr(f, "stop_here"))) + self.assertIs(unwrapped, func2) + + def test_cycle(self): + def func1(): pass + func1.__wrapped__ = func1 + with self.assertRaisesRegex(ValueError, 'wrapper loop'): + inspect.unwrap(func1) + + def func2(): pass + func2.__wrapped__ = func1 + func1.__wrapped__ = func2 + with self.assertRaisesRegex(ValueError, 'wrapper loop'): + inspect.unwrap(func1) + with self.assertRaisesRegex(ValueError, 'wrapper loop'): + inspect.unwrap(func2) + + def test_unhashable(self): + def func(): pass + func.__wrapped__ = None + class C: + __hash__ = None + __wrapped__ = func + self.assertIsNone(inspect.unwrap(C())) + + def test_main(): run_unittest( TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases, @@ -2291,7 +2363,7 @@ TestGetcallargsFunctions, TestGetcallargsMethods, TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState, TestNoEOL, TestSignatureObject, TestSignatureBind, TestParameterObject, - TestBoundArguments, TestGetClosureVars + TestBoundArguments, TestGetClosureVars, TestUnwrap ) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -171,6 +171,9 @@ Library ------- +- Issue #13266: Added inspect.unwrap to easily unravel __wrapped__ chains + (initial patch by Daniel Urban and Aaron Iles) + - Issue #18561: Skip name in ctypes' _build_callargs() if name is NULL. - Issue #18559: Fix NULL pointer dereference error in _pickle module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 12:56:44 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 28 Jul 2013 12:56:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2315494=3A_test=2Es?= =?utf-8?q?upport_is_now_a_package_rather_than_a_module?= Message-ID: <3c31Dr5hjXz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/203a77e74aa7 changeset: 84884:203a77e74aa7 user: Nick Coghlan date: Sun Jul 28 20:56:19 2013 +1000 summary: Close #15494: test.support is now a package rather than a module Initial patch by Indra Talip files: Lib/test/support.py | 7 +++++-- Lib/test/test_linecache.py | 2 +- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support/__init__.py rename from Lib/test/support.py rename to Lib/test/support/__init__.py --- a/Lib/test/support.py +++ b/Lib/test/support/__init__.py @@ -789,9 +789,12 @@ finally: os.umask(oldmask) +# TEST_HOME refers to the top level directory of the "test" package +# that contains Python's regression test suite +TEST_HOME = os.path.dirname(os.path.abspath(__file__)) -def findfile(file, here=__file__, subdir=None): - """Try to find a file on sys.path and the working directory. If it is not +def findfile(file, here=TEST_HOME, subdir=None): + """Try to find a file on sys.path or in the test directory. If it is not found the argument passed to the function is returned (this does not necessarily signal failure; could still be the legitimate path).""" if os.path.isabs(file): diff --git a/Lib/test/test_linecache.py b/Lib/test/test_linecache.py --- a/Lib/test/test_linecache.py +++ b/Lib/test/test_linecache.py @@ -11,7 +11,7 @@ EMPTY = '' TESTS = 'inspect_fodder inspect_fodder2 mapping_tests' TESTS = TESTS.split() -TEST_PATH = os.path.dirname(support.__file__) +TEST_PATH = os.path.dirname(__file__) MODULES = "linecache abc".split() MODULE_PATH = os.path.dirname(FILENAME) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1237,6 +1237,7 @@ Amir Szekely Arfrever Frehtes Taifersar Arahesis Hideaki Takahashi +Indra Talip Neil Tallim Geoff Talvola Musashi Tamura diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -571,6 +571,9 @@ Tests ----- +- Issue #15494: test.support is now a package rather than a module (Initial + patch by Indra Talip) + - Issue #17944: test_zipfile now discoverable and uses subclassing to generate tests for different compression types. Fixed a bug with skipping some tests due to use of exhausted iterators. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 13:41:15 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 28 Jul 2013 13:41:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1NDk0?= =?utf-8?q?=3A_test=2Esupport_is_now_a_package_rather_than_a_module?= Message-ID: <3c32DC1Xx7z7LlD@mail.python.org> http://hg.python.org/cpython/rev/0b7ed24f7d33 changeset: 84885:0b7ed24f7d33 branch: 3.3 parent: 84878:c3936a52f215 user: Nick Coghlan date: Sun Jul 28 21:06:50 2013 +1000 summary: Issue #15494: test.support is now a package rather than a module Also including this change in 3.3 to help avoid spurious conflicts between the two most active branches. (Initial patch by Indra Talip) files: Lib/test/support.py | 7 +++++-- Lib/test/test_linecache.py | 2 +- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support/__init__.py rename from Lib/test/support.py rename to Lib/test/support/__init__.py --- a/Lib/test/support.py +++ b/Lib/test/support/__init__.py @@ -787,9 +787,12 @@ finally: os.umask(oldmask) +# TEST_HOME refers to the top level directory of the "test" package +# that contains Python's regression test suite +TEST_HOME = os.path.dirname(os.path.abspath(__file__)) -def findfile(file, here=__file__, subdir=None): - """Try to find a file on sys.path and the working directory. If it is not +def findfile(file, here=TEST_HOME, subdir=None): + """Try to find a file on sys.path or in the test directory. If it is not found the argument passed to the function is returned (this does not necessarily signal failure; could still be the legitimate path).""" if os.path.isabs(file): diff --git a/Lib/test/test_linecache.py b/Lib/test/test_linecache.py --- a/Lib/test/test_linecache.py +++ b/Lib/test/test_linecache.py @@ -11,7 +11,7 @@ EMPTY = '' TESTS = 'inspect_fodder inspect_fodder2 mapping_tests' TESTS = TESTS.split() -TEST_PATH = os.path.dirname(support.__file__) +TEST_PATH = os.path.dirname(__file__) MODULES = "linecache abc".split() MODULE_PATH = os.path.dirname(FILENAME) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1202,6 +1202,7 @@ P?ter Szab? Amir Szekely Arfrever Frehtes Taifersar Arahesis +Indra Talip Neil Tallim Geoff Talvola Musashi Tamura diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -222,6 +222,9 @@ Tests ----- +- Issue #15494: test.support is now a package rather than a module (Initial + patch by Indra Talip) + - Issue #17944: test_zipfile now discoverable and uses subclassing to generate tests for different compression types. Fixed a bug with skipping some tests due to use of exhausted iterators. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 13:41:16 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 28 Jul 2013 13:41:16 +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: <3c32DD3Ws7z7LlQ@mail.python.org> http://hg.python.org/cpython/rev/4513ee4d953b changeset: 84886:4513ee4d953b parent: 84884:203a77e74aa7 parent: 84885:0b7ed24f7d33 user: Nick Coghlan date: Sun Jul 28 21:40:20 2013 +1000 summary: Null merge from 3.3 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 14:25:49 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 28 Jul 2013 14:25:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogQ2xvc2UgIzE1NDE1?= =?utf-8?q?=3A_Factor_out_temp_dir_helpers_to_test=2Esupport?= Message-ID: <3c33Cd2Mh8zQCG@mail.python.org> http://hg.python.org/cpython/rev/4f0034477ba9 changeset: 84887:4f0034477ba9 branch: 3.3 parent: 84885:0b7ed24f7d33 user: Nick Coghlan date: Sun Jul 28 22:11:50 2013 +1000 summary: Close #15415: Factor out temp dir helpers to test.support Patch by Chris Jerdonek files: Doc/library/test.rst | 38 ++++- Lib/test/script_helper.py | 12 +- Lib/test/support/__init__.py | 80 ++++++++-- Lib/test/test_cmd_line_script.py | 8 +- Lib/test/test_shutil.py | 10 +- Lib/test/test_support.py | 130 +++++++++++++++++- Misc/NEWS | 3 + 7 files changed, 225 insertions(+), 56 deletions(-) diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -387,18 +387,40 @@ self.assertEqual(captured, "hello") -.. function:: temp_cwd(name='tempcwd', quiet=False, path=None) +.. function:: temp_dir(path=None, quiet=False) + + A context manager that creates a temporary directory at *path* and + yields the directory. + + If *path* is None, the temporary directory is created using + :func:`tempfile.mkdtemp`. If *quiet* is ``False``, the context manager + raises an exception on error. Otherwise, if *path* is specified and + cannot be created, only a warning is issued. + + +.. function:: change_cwd(path, quiet=False) A context manager that temporarily changes the current working - directory (CWD). + directory to *path* and yields the directory. - An existing path may be provided as *path*, in which case this function - makes no changes to the file system. + If *quiet* is ``False``, the context manager raises an exception + on error. Otherwise, it issues only a warning and keeps the current + working directory the same. - Otherwise, the new CWD is created in the current directory and it's named - *name*. If *quiet* is ``False`` and it's not possible to create or - change the CWD, an error is raised. If it's ``True``, only a warning - is raised and the original CWD is used. + +.. function:: temp_cwd(name='tempcwd', quiet=False) + + A context manager that temporarily creates a new directory and + changes the current working directory (CWD). + + The context manager creates a temporary directory in the current + directory with name *name* before temporarily changing the current + working directory. If *name* is None, the temporary directory is + created using :func:`tempfile.mkdtemp`. + + If *quiet* is ``False`` and it is not possible to create or change + the CWD, an error is raised. Otherwise, only a warning is raised + and the original CWD is used. .. function:: temp_umask(umask) diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -13,7 +13,7 @@ import zipfile from imp import source_from_cache -from test.support import make_legacy_pyc, strip_python_stderr +from test.support import make_legacy_pyc, strip_python_stderr, temp_dir # Executing the interpreter in a subprocess def _assert_python(expected_success, *args, **env_vars): @@ -77,16 +77,6 @@ subprocess._cleanup() return data -# Script creation utilities - at contextlib.contextmanager -def temp_dir(): - dirname = tempfile.mkdtemp() - dirname = os.path.realpath(dirname) - try: - yield dirname - finally: - shutil.rmtree(dirname) - def make_script(script_dir, script_basename, source): script_filename = script_basename+os.extsep+'py' script_name = os.path.join(script_dir, script_filename) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -738,45 +738,85 @@ SAVEDCWD = os.getcwd() @contextlib.contextmanager -def temp_cwd(name='tempcwd', quiet=False, path=None): +def temp_dir(path=None, quiet=False): + """Return a context manager that creates a temporary directory. + + Arguments: + + path: the directory to create temporarily. If omitted or None, + defaults to creating a temporary directory using tempfile.mkdtemp. + + quiet: if False (the default), the context manager raises an exception + on error. Otherwise, if the path is specified and cannot be + created, only a warning is issued. + """ - Context manager that temporarily changes the CWD. - - An existing path may be provided as *path*, in which case this - function makes no changes to the file system. - - Otherwise, the new CWD is created in the current directory and it's - named *name*. If *quiet* is False (default) and it's not possible to - create or change the CWD, an error is raised. If it's True, only a - warning is raised and the original CWD is used. - """ - saved_dir = os.getcwd() - is_temporary = False + dir_created = False if path is None: - path = name + path = tempfile.mkdtemp() + dir_created = True + path = os.path.realpath(path) + else: try: - os.mkdir(name) - is_temporary = True + os.mkdir(path) + dir_created = True except OSError: if not quiet: raise - warnings.warn('tests may fail, unable to create temp CWD ' + name, + warnings.warn('tests may fail, unable to create temp dir: ' + path, RuntimeWarning, stacklevel=3) try: + yield path + finally: + if dir_created: + shutil.rmtree(path) + + at contextlib.contextmanager +def change_cwd(path, quiet=False): + """Return a context manager that changes the current working directory. + + Arguments: + + path: the directory to use as the temporary current working directory. + + quiet: if False (the default), the context manager raises an exception + on error. Otherwise, it issues only a warning and keeps the current + working directory the same. + + """ + saved_dir = os.getcwd() + try: os.chdir(path) except OSError: if not quiet: raise - warnings.warn('tests may fail, unable to change the CWD to ' + path, + warnings.warn('tests may fail, unable to change CWD to: ' + path, RuntimeWarning, stacklevel=3) try: yield os.getcwd() finally: os.chdir(saved_dir) - if is_temporary: - rmtree(name) + at contextlib.contextmanager +def temp_cwd(name='tempcwd', quiet=False): + """ + Context manager that temporarily creates and changes the CWD. + + The function temporarily changes the current working directory + after creating a temporary directory in the current directory with + name *name*. If *name* is None, the temporary directory is + created using tempfile.mkdtemp. + + If *quiet* is False (default) and it is not possible to + create or change the CWD, an error is raised. If *quiet* is True, + only a warning is raised and the original CWD is used. + + """ + with temp_dir(path=name, quiet=quiet) as temp_path: + with change_cwd(temp_path, quiet=quiet) as cwd_dir: + yield cwd_dir + if hasattr(os, "umask"): @contextlib.contextmanager def temp_umask(umask): diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -290,7 +290,7 @@ # Make sure package __init__ modules see "-m" in sys.argv0 while # searching for the module to execute with temp_dir() as script_dir: - with support.temp_cwd(path=script_dir): + with support.change_cwd(path=script_dir): pkg_dir = os.path.join(script_dir, 'test_pkg') make_pkg(pkg_dir, "import sys; print('init_argv0==%r' % sys.argv[0])") script_name = _make_test_script(pkg_dir, 'script') @@ -307,7 +307,7 @@ # Make sure a "-c" file in the current directory # does not alter the value of sys.path[0] with temp_dir() as script_dir: - with support.temp_cwd(path=script_dir): + with support.change_cwd(path=script_dir): with open("-c", "w") as f: f.write("data") rc, out, err = assert_python_ok('-c', @@ -322,7 +322,7 @@ # does not alter the value of sys.path[0] with temp_dir() as script_dir: script_name = _make_test_script(script_dir, 'other') - with support.temp_cwd(path=script_dir): + with support.change_cwd(path=script_dir): with open("-m", "w") as f: f.write("data") rc, out, err = assert_python_ok('-m', 'other', *example_args) @@ -335,7 +335,7 @@ # and results in an error that the return code to the # shell is '1' with temp_dir() as script_dir: - with support.temp_cwd(path=script_dir): + with support.change_cwd(path=script_dir): pkg_dir = os.path.join(script_dir, 'test_pkg') make_pkg(pkg_dir) script_name = _make_test_script(pkg_dir, 'other', 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 @@ -1307,18 +1307,18 @@ # that exists, it should be returned. base_dir, tail_dir = os.path.split(self.dir) relpath = os.path.join(tail_dir, self.file) - with support.temp_cwd(path=base_dir): + with support.change_cwd(path=base_dir): rv = shutil.which(relpath, path=self.temp_dir) self.assertEqual(rv, relpath) # But it shouldn't be searched in PATH directories (issue #16957). - with support.temp_cwd(path=self.dir): + with support.change_cwd(path=self.dir): rv = shutil.which(relpath, path=base_dir) self.assertIsNone(rv) def test_cwd(self): # Issue #16957 base_dir = os.path.dirname(self.dir) - with support.temp_cwd(path=self.dir): + with support.change_cwd(path=self.dir): rv = shutil.which(self.file, path=base_dir) if sys.platform == "win32": # Windows: current directory implicitly on PATH @@ -1339,7 +1339,7 @@ def test_relative_path(self): base_dir, tail_dir = os.path.split(self.dir) - with support.temp_cwd(path=base_dir): + with support.change_cwd(path=base_dir): rv = shutil.which(self.file, path=tail_dir) self.assertEqual(rv, os.path.join(tail_dir, self.file)) @@ -1364,7 +1364,7 @@ def test_empty_path(self): base_dir = os.path.dirname(self.dir) - with support.temp_cwd(path=self.dir), \ + with support.change_cwd(path=self.dir), \ support.EnvironmentVarGuard() as env: env['PATH'] = self.dir rv = shutil.which(self.file, path='') diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import importlib +import shutil import sys import os import unittest @@ -88,6 +89,118 @@ s.listen(1) s.close() + # Tests for temp_dir() + + def test_temp_dir(self): + """Test that temp_dir() creates and destroys its directory.""" + parent_dir = tempfile.mkdtemp() + parent_dir = os.path.realpath(parent_dir) + + try: + path = os.path.join(parent_dir, 'temp') + self.assertFalse(os.path.isdir(path)) + with support.temp_dir(path) as temp_path: + self.assertEqual(temp_path, path) + self.assertTrue(os.path.isdir(path)) + self.assertFalse(os.path.isdir(path)) + finally: + shutil.rmtree(parent_dir) + + def test_temp_dir__path_none(self): + """Test passing no path.""" + with support.temp_dir() as temp_path: + self.assertTrue(os.path.isdir(temp_path)) + self.assertFalse(os.path.isdir(temp_path)) + + def test_temp_dir__existing_dir__quiet_default(self): + """Test passing a directory that already exists.""" + def call_temp_dir(path): + with support.temp_dir(path) as temp_path: + raise Exception("should not get here") + + path = tempfile.mkdtemp() + path = os.path.realpath(path) + try: + self.assertTrue(os.path.isdir(path)) + self.assertRaises(FileExistsError, call_temp_dir, path) + # Make sure temp_dir did not delete the original directory. + self.assertTrue(os.path.isdir(path)) + finally: + shutil.rmtree(path) + + def test_temp_dir__existing_dir__quiet_true(self): + """Test passing a directory that already exists with quiet=True.""" + path = tempfile.mkdtemp() + path = os.path.realpath(path) + + try: + with support.check_warnings() as recorder: + with support.temp_dir(path, quiet=True) as temp_path: + self.assertEqual(path, temp_path) + warnings = [str(w.message) for w in recorder.warnings] + # Make sure temp_dir did not delete the original directory. + self.assertTrue(os.path.isdir(path)) + finally: + shutil.rmtree(path) + + expected = ['tests may fail, unable to create temp dir: ' + path] + self.assertEqual(warnings, expected) + + # Tests for change_cwd() + + def test_change_cwd(self): + original_cwd = os.getcwd() + + with support.temp_dir() as temp_path: + with support.change_cwd(temp_path) as new_cwd: + self.assertEqual(new_cwd, temp_path) + self.assertEqual(os.getcwd(), new_cwd) + + self.assertEqual(os.getcwd(), original_cwd) + + def test_change_cwd__non_existent_dir(self): + """Test passing a non-existent directory.""" + original_cwd = os.getcwd() + + def call_change_cwd(path): + with support.change_cwd(path) as new_cwd: + raise Exception("should not get here") + + with support.temp_dir() as parent_dir: + non_existent_dir = os.path.join(parent_dir, 'does_not_exist') + self.assertRaises(FileNotFoundError, call_change_cwd, + non_existent_dir) + + self.assertEqual(os.getcwd(), original_cwd) + + def test_change_cwd__non_existent_dir__quiet_true(self): + """Test passing a non-existent directory with quiet=True.""" + original_cwd = os.getcwd() + + with support.temp_dir() as parent_dir: + bad_dir = os.path.join(parent_dir, 'does_not_exist') + with support.check_warnings() as recorder: + with support.change_cwd(bad_dir, quiet=True) as new_cwd: + self.assertEqual(new_cwd, original_cwd) + self.assertEqual(os.getcwd(), new_cwd) + warnings = [str(w.message) for w in recorder.warnings] + + expected = ['tests may fail, unable to change CWD to: ' + bad_dir] + self.assertEqual(warnings, expected) + + # Tests for change_cwd() + + def test_change_cwd__chdir_warning(self): + """Check the warning message when os.chdir() fails.""" + path = TESTFN + '_does_not_exist' + with support.check_warnings() as recorder: + with support.change_cwd(path=path, quiet=True): + pass + messages = [str(w.message) for w in recorder.warnings] + self.assertEqual(messages, ['tests may fail, unable to change CWD to: ' + path]) + + # Tests for temp_cwd() + def test_temp_cwd(self): here = os.getcwd() with support.temp_cwd(name=TESTFN): @@ -95,14 +208,15 @@ self.assertFalse(os.path.exists(TESTFN)) self.assertTrue(os.path.basename(os.getcwd()), here) - def test_temp_cwd__chdir_warning(self): - """Check the warning message when os.chdir() fails.""" - path = TESTFN + '_does_not_exist' - with support.check_warnings() as recorder: - with support.temp_cwd(path=path, quiet=True): - pass - messages = [str(w.message) for w in recorder.warnings] - self.assertEqual(messages, ['tests may fail, unable to change the CWD to ' + path]) + + def test_temp_cwd__name_none(self): + """Test passing None to temp_cwd().""" + original_cwd = os.getcwd() + with support.temp_cwd(name=None) as new_cwd: + self.assertNotEqual(new_cwd, original_cwd) + self.assertTrue(os.path.isdir(new_cwd)) + self.assertEqual(os.getcwd(), new_cwd) + self.assertEqual(os.getcwd(), original_cwd) def test_sortdict(self): self.assertEqual(support.sortdict({3:3, 2:2, 1:1}), "{1: 1, 2: 2, 3: 3}") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -222,6 +222,9 @@ Tests ----- +- Issue #15415: Add new temp_dir() and change_cwd() context managers to + test.support, and refactor temp_cwd() to use them. Patch by Chris Jerdonek. + - Issue #15494: test.support is now a package rather than a module (Initial patch by Indra Talip) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 14:25:50 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 28 Jul 2013 14:25:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2315415_from_3=2E3?= Message-ID: <3c33Cf6k8hz7Ll7@mail.python.org> http://hg.python.org/cpython/rev/b20a10c97e08 changeset: 84888:b20a10c97e08 parent: 84886:4513ee4d953b parent: 84887:4f0034477ba9 user: Nick Coghlan date: Sun Jul 28 22:25:25 2013 +1000 summary: Merge #15415 from 3.3 files: Doc/library/test.rst | 38 ++++- Lib/test/script_helper.py | 12 +- Lib/test/support/__init__.py | 80 ++++++++-- Lib/test/test_cmd_line_script.py | 8 +- Lib/test/test_shutil.py | 10 +- Lib/test/test_support.py | 130 +++++++++++++++++- Misc/NEWS | 3 + 7 files changed, 225 insertions(+), 56 deletions(-) diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -387,18 +387,40 @@ self.assertEqual(captured, "hello") -.. function:: temp_cwd(name='tempcwd', quiet=False, path=None) +.. function:: temp_dir(path=None, quiet=False) + + A context manager that creates a temporary directory at *path* and + yields the directory. + + If *path* is None, the temporary directory is created using + :func:`tempfile.mkdtemp`. If *quiet* is ``False``, the context manager + raises an exception on error. Otherwise, if *path* is specified and + cannot be created, only a warning is issued. + + +.. function:: change_cwd(path, quiet=False) A context manager that temporarily changes the current working - directory (CWD). + directory to *path* and yields the directory. - An existing path may be provided as *path*, in which case this function - makes no changes to the file system. + If *quiet* is ``False``, the context manager raises an exception + on error. Otherwise, it issues only a warning and keeps the current + working directory the same. - Otherwise, the new CWD is created in the current directory and it's named - *name*. If *quiet* is ``False`` and it's not possible to create or - change the CWD, an error is raised. If it's ``True``, only a warning - is raised and the original CWD is used. + +.. function:: temp_cwd(name='tempcwd', quiet=False) + + A context manager that temporarily creates a new directory and + changes the current working directory (CWD). + + The context manager creates a temporary directory in the current + directory with name *name* before temporarily changing the current + working directory. If *name* is None, the temporary directory is + created using :func:`tempfile.mkdtemp`. + + If *quiet* is ``False`` and it is not possible to create or change + the CWD, an error is raised. Otherwise, only a warning is raised + and the original CWD is used. .. function:: temp_umask(umask) diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -13,7 +13,7 @@ import zipfile from importlib.util import source_from_cache -from test.support import make_legacy_pyc, strip_python_stderr +from test.support import make_legacy_pyc, strip_python_stderr, temp_dir # Executing the interpreter in a subprocess def _assert_python(expected_success, *args, **env_vars): @@ -77,16 +77,6 @@ subprocess._cleanup() return data -# Script creation utilities - at contextlib.contextmanager -def temp_dir(): - dirname = tempfile.mkdtemp() - dirname = os.path.realpath(dirname) - try: - yield dirname - finally: - shutil.rmtree(dirname) - def make_script(script_dir, script_basename, source): script_filename = script_basename+os.extsep+'py' script_name = os.path.join(script_dir, script_filename) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -740,45 +740,85 @@ SAVEDCWD = os.getcwd() @contextlib.contextmanager -def temp_cwd(name='tempcwd', quiet=False, path=None): +def temp_dir(path=None, quiet=False): + """Return a context manager that creates a temporary directory. + + Arguments: + + path: the directory to create temporarily. If omitted or None, + defaults to creating a temporary directory using tempfile.mkdtemp. + + quiet: if False (the default), the context manager raises an exception + on error. Otherwise, if the path is specified and cannot be + created, only a warning is issued. + """ - Context manager that temporarily changes the CWD. - - An existing path may be provided as *path*, in which case this - function makes no changes to the file system. - - Otherwise, the new CWD is created in the current directory and it's - named *name*. If *quiet* is False (default) and it's not possible to - create or change the CWD, an error is raised. If it's True, only a - warning is raised and the original CWD is used. - """ - saved_dir = os.getcwd() - is_temporary = False + dir_created = False if path is None: - path = name + path = tempfile.mkdtemp() + dir_created = True + path = os.path.realpath(path) + else: try: - os.mkdir(name) - is_temporary = True + os.mkdir(path) + dir_created = True except OSError: if not quiet: raise - warnings.warn('tests may fail, unable to create temp CWD ' + name, + warnings.warn('tests may fail, unable to create temp dir: ' + path, RuntimeWarning, stacklevel=3) try: + yield path + finally: + if dir_created: + shutil.rmtree(path) + + at contextlib.contextmanager +def change_cwd(path, quiet=False): + """Return a context manager that changes the current working directory. + + Arguments: + + path: the directory to use as the temporary current working directory. + + quiet: if False (the default), the context manager raises an exception + on error. Otherwise, it issues only a warning and keeps the current + working directory the same. + + """ + saved_dir = os.getcwd() + try: os.chdir(path) except OSError: if not quiet: raise - warnings.warn('tests may fail, unable to change the CWD to ' + path, + warnings.warn('tests may fail, unable to change CWD to: ' + path, RuntimeWarning, stacklevel=3) try: yield os.getcwd() finally: os.chdir(saved_dir) - if is_temporary: - rmtree(name) + at contextlib.contextmanager +def temp_cwd(name='tempcwd', quiet=False): + """ + Context manager that temporarily creates and changes the CWD. + + The function temporarily changes the current working directory + after creating a temporary directory in the current directory with + name *name*. If *name* is None, the temporary directory is + created using tempfile.mkdtemp. + + If *quiet* is False (default) and it is not possible to + create or change the CWD, an error is raised. If *quiet* is True, + only a warning is raised and the original CWD is used. + + """ + with temp_dir(path=name, quiet=quiet) as temp_path: + with change_cwd(temp_path, quiet=quiet) as cwd_dir: + yield cwd_dir + if hasattr(os, "umask"): @contextlib.contextmanager def temp_umask(umask): diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -290,7 +290,7 @@ # Make sure package __init__ modules see "-m" in sys.argv0 while # searching for the module to execute with temp_dir() as script_dir: - with support.temp_cwd(path=script_dir): + with support.change_cwd(path=script_dir): pkg_dir = os.path.join(script_dir, 'test_pkg') make_pkg(pkg_dir, "import sys; print('init_argv0==%r' % sys.argv[0])") script_name = _make_test_script(pkg_dir, 'script') @@ -307,7 +307,7 @@ # Make sure a "-c" file in the current directory # does not alter the value of sys.path[0] with temp_dir() as script_dir: - with support.temp_cwd(path=script_dir): + with support.change_cwd(path=script_dir): with open("-c", "w") as f: f.write("data") rc, out, err = assert_python_ok('-c', @@ -322,7 +322,7 @@ # does not alter the value of sys.path[0] with temp_dir() as script_dir: script_name = _make_test_script(script_dir, 'other') - with support.temp_cwd(path=script_dir): + with support.change_cwd(path=script_dir): with open("-m", "w") as f: f.write("data") rc, out, err = assert_python_ok('-m', 'other', *example_args) @@ -335,7 +335,7 @@ # and results in an error that the return code to the # shell is '1' with temp_dir() as script_dir: - with support.temp_cwd(path=script_dir): + with support.change_cwd(path=script_dir): pkg_dir = os.path.join(script_dir, 'test_pkg') make_pkg(pkg_dir) script_name = _make_test_script(pkg_dir, 'other', 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 @@ -1318,18 +1318,18 @@ # that exists, it should be returned. base_dir, tail_dir = os.path.split(self.dir) relpath = os.path.join(tail_dir, self.file) - with support.temp_cwd(path=base_dir): + with support.change_cwd(path=base_dir): rv = shutil.which(relpath, path=self.temp_dir) self.assertEqual(rv, relpath) # But it shouldn't be searched in PATH directories (issue #16957). - with support.temp_cwd(path=self.dir): + with support.change_cwd(path=self.dir): rv = shutil.which(relpath, path=base_dir) self.assertIsNone(rv) def test_cwd(self): # Issue #16957 base_dir = os.path.dirname(self.dir) - with support.temp_cwd(path=self.dir): + with support.change_cwd(path=self.dir): rv = shutil.which(self.file, path=base_dir) if sys.platform == "win32": # Windows: current directory implicitly on PATH @@ -1350,7 +1350,7 @@ def test_relative_path(self): base_dir, tail_dir = os.path.split(self.dir) - with support.temp_cwd(path=base_dir): + with support.change_cwd(path=base_dir): rv = shutil.which(self.file, path=tail_dir) self.assertEqual(rv, os.path.join(tail_dir, self.file)) @@ -1375,7 +1375,7 @@ def test_empty_path(self): base_dir = os.path.dirname(self.dir) - with support.temp_cwd(path=self.dir), \ + with support.change_cwd(path=self.dir), \ support.EnvironmentVarGuard() as env: env['PATH'] = self.dir rv = shutil.which(self.file, path='') diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import importlib +import shutil import sys import os import unittest @@ -88,6 +89,118 @@ s.listen(1) s.close() + # Tests for temp_dir() + + def test_temp_dir(self): + """Test that temp_dir() creates and destroys its directory.""" + parent_dir = tempfile.mkdtemp() + parent_dir = os.path.realpath(parent_dir) + + try: + path = os.path.join(parent_dir, 'temp') + self.assertFalse(os.path.isdir(path)) + with support.temp_dir(path) as temp_path: + self.assertEqual(temp_path, path) + self.assertTrue(os.path.isdir(path)) + self.assertFalse(os.path.isdir(path)) + finally: + shutil.rmtree(parent_dir) + + def test_temp_dir__path_none(self): + """Test passing no path.""" + with support.temp_dir() as temp_path: + self.assertTrue(os.path.isdir(temp_path)) + self.assertFalse(os.path.isdir(temp_path)) + + def test_temp_dir__existing_dir__quiet_default(self): + """Test passing a directory that already exists.""" + def call_temp_dir(path): + with support.temp_dir(path) as temp_path: + raise Exception("should not get here") + + path = tempfile.mkdtemp() + path = os.path.realpath(path) + try: + self.assertTrue(os.path.isdir(path)) + self.assertRaises(FileExistsError, call_temp_dir, path) + # Make sure temp_dir did not delete the original directory. + self.assertTrue(os.path.isdir(path)) + finally: + shutil.rmtree(path) + + def test_temp_dir__existing_dir__quiet_true(self): + """Test passing a directory that already exists with quiet=True.""" + path = tempfile.mkdtemp() + path = os.path.realpath(path) + + try: + with support.check_warnings() as recorder: + with support.temp_dir(path, quiet=True) as temp_path: + self.assertEqual(path, temp_path) + warnings = [str(w.message) for w in recorder.warnings] + # Make sure temp_dir did not delete the original directory. + self.assertTrue(os.path.isdir(path)) + finally: + shutil.rmtree(path) + + expected = ['tests may fail, unable to create temp dir: ' + path] + self.assertEqual(warnings, expected) + + # Tests for change_cwd() + + def test_change_cwd(self): + original_cwd = os.getcwd() + + with support.temp_dir() as temp_path: + with support.change_cwd(temp_path) as new_cwd: + self.assertEqual(new_cwd, temp_path) + self.assertEqual(os.getcwd(), new_cwd) + + self.assertEqual(os.getcwd(), original_cwd) + + def test_change_cwd__non_existent_dir(self): + """Test passing a non-existent directory.""" + original_cwd = os.getcwd() + + def call_change_cwd(path): + with support.change_cwd(path) as new_cwd: + raise Exception("should not get here") + + with support.temp_dir() as parent_dir: + non_existent_dir = os.path.join(parent_dir, 'does_not_exist') + self.assertRaises(FileNotFoundError, call_change_cwd, + non_existent_dir) + + self.assertEqual(os.getcwd(), original_cwd) + + def test_change_cwd__non_existent_dir__quiet_true(self): + """Test passing a non-existent directory with quiet=True.""" + original_cwd = os.getcwd() + + with support.temp_dir() as parent_dir: + bad_dir = os.path.join(parent_dir, 'does_not_exist') + with support.check_warnings() as recorder: + with support.change_cwd(bad_dir, quiet=True) as new_cwd: + self.assertEqual(new_cwd, original_cwd) + self.assertEqual(os.getcwd(), new_cwd) + warnings = [str(w.message) for w in recorder.warnings] + + expected = ['tests may fail, unable to change CWD to: ' + bad_dir] + self.assertEqual(warnings, expected) + + # Tests for change_cwd() + + def test_change_cwd__chdir_warning(self): + """Check the warning message when os.chdir() fails.""" + path = TESTFN + '_does_not_exist' + with support.check_warnings() as recorder: + with support.change_cwd(path=path, quiet=True): + pass + messages = [str(w.message) for w in recorder.warnings] + self.assertEqual(messages, ['tests may fail, unable to change CWD to: ' + path]) + + # Tests for temp_cwd() + def test_temp_cwd(self): here = os.getcwd() with support.temp_cwd(name=TESTFN): @@ -95,14 +208,15 @@ self.assertFalse(os.path.exists(TESTFN)) self.assertTrue(os.path.basename(os.getcwd()), here) - def test_temp_cwd__chdir_warning(self): - """Check the warning message when os.chdir() fails.""" - path = TESTFN + '_does_not_exist' - with support.check_warnings() as recorder: - with support.temp_cwd(path=path, quiet=True): - pass - messages = [str(w.message) for w in recorder.warnings] - self.assertEqual(messages, ['tests may fail, unable to change the CWD to ' + path]) + + def test_temp_cwd__name_none(self): + """Test passing None to temp_cwd().""" + original_cwd = os.getcwd() + with support.temp_cwd(name=None) as new_cwd: + self.assertNotEqual(new_cwd, original_cwd) + self.assertTrue(os.path.isdir(new_cwd)) + self.assertEqual(os.getcwd(), new_cwd) + self.assertEqual(os.getcwd(), original_cwd) def test_sortdict(self): self.assertEqual(support.sortdict({3:3, 2:2, 1:1}), "{1: 1, 2: 2, 3: 3}") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -571,6 +571,9 @@ Tests ----- +- Issue #15415: Add new temp_dir() and change_cwd() context managers to + test.support, and refactor temp_cwd() to use them. Patch by Chris Jerdonek. + - Issue #15494: test.support is now a package rather than a module (Initial patch by Indra Talip) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 22:26:16 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 22:26:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_Remove_check_from_test=5Ftext=2Epy_in_3=2E3=2C4_=28already_?= =?utf-8?q?done_in_2=2E7=29=2E?= Message-ID: <3c3Ft05Jvdz7Lky@mail.python.org> http://hg.python.org/cpython/rev/c57b2a344097 changeset: 84889:c57b2a344097 branch: 3.3 parent: 84887:4f0034477ba9 user: Terry Jan Reedy date: Sun Jul 28 16:25:16 2013 -0400 summary: Issue #18441: Remove check from test_text.py in 3.3,4 (already done in 2.7). files: Lib/idlelib/idle_test/test_text.py | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -216,10 +216,7 @@ requires('gui') from tkinter import Tk, Text cls.Text = Text - try: - cls.root = Tk() - except TclError as msg: - raise unittest.SkipTest('TclError: %s' % msg) + cls.root = Tk() @classmethod def tearDownClass(cls): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 22:26:18 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 22:26:18 +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: <3c3Ft206Znz7Lky@mail.python.org> http://hg.python.org/cpython/rev/f8c0062aa12c changeset: 84890:f8c0062aa12c parent: 84888:b20a10c97e08 parent: 84889:c57b2a344097 user: Terry Jan Reedy date: Sun Jul 28 16:25:52 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/idle_test/test_text.py | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -216,10 +216,7 @@ requires('gui') from tkinter import Tk, Text cls.Text = Text - try: - cls.root = Tk() - except TclError as msg: - raise unittest.SkipTest('TclError: %s' % msg) + cls.root = Tk() @classmethod def tearDownClass(cls): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 22:41:13 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 22:41:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Update_gui_sec?= =?utf-8?q?tion_of_idle_test_README=2E?= Message-ID: <3c3GCF5Rlkz7Lkt@mail.python.org> http://hg.python.org/cpython/rev/70a4287a25b4 changeset: 84891:70a4287a25b4 branch: 3.3 parent: 84889:c57b2a344097 user: Terry Jan Reedy date: Sun Jul 28 16:39:44 2013 -0400 summary: Update gui section of idle test README. files: Lib/idlelib/idle_test/README.txt | 16 ++++++++++++---- 1 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/idle_test/README.txt b/Lib/idlelib/idle_test/README.txt --- a/Lib/idlelib/idle_test/README.txt +++ b/Lib/idlelib/idle_test/README.txt @@ -40,13 +40,20 @@ idle class. For the benefit of buildbot machines that do not have a graphics screen, gui tests must be 'guarded' by "requires('gui')" in a setUp function or method. This will typically be setUpClass. + +All gui objects must be destroyed by the end of the test, perhaps in a tearDown +function. Creating the Tk root directly in a setUp allows a reference to be saved +so it can be properly destroyed in the corresponding tearDown. --- @classmethod def setUpClass(cls): requires('gui') + cls.root = tk.Tk() + + @classmethod + def tearDownClass(cls): + cls.root.destroy() --- -All gui objects must be destroyed by the end of the test, perhaps in a tearDown -function. Support.requires('gui') returns true if it is either called in a main module (which never happens on buildbots) or if use_resources contains 'gui'. @@ -56,8 +63,9 @@ Since non-gui tests always run, but gui tests only sometimes, tests of non-gui operations should best avoid needing a gui. Methods that make incidental use of -tkinter variables and messageboxes can do this by using the mock classes in -idle_test/mock_tk.py. +tkinter (tk) variables and messageboxes can do this by using the mock classes in +idle_test/mock_tk.py. There is also a mock text that will handle some uses of the +tk Text widget. 3. Running Tests -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 22:41:15 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 22:41:15 +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: <3c3GCH09Byz7Lky@mail.python.org> http://hg.python.org/cpython/rev/4d08db5edbaa changeset: 84892:4d08db5edbaa parent: 84890:f8c0062aa12c parent: 84891:70a4287a25b4 user: Terry Jan Reedy date: Sun Jul 28 16:40:07 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/idle_test/README.txt | 16 ++++++++++++---- 1 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/idle_test/README.txt b/Lib/idlelib/idle_test/README.txt --- a/Lib/idlelib/idle_test/README.txt +++ b/Lib/idlelib/idle_test/README.txt @@ -40,13 +40,20 @@ idle class. For the benefit of buildbot machines that do not have a graphics screen, gui tests must be 'guarded' by "requires('gui')" in a setUp function or method. This will typically be setUpClass. + +All gui objects must be destroyed by the end of the test, perhaps in a tearDown +function. Creating the Tk root directly in a setUp allows a reference to be saved +so it can be properly destroyed in the corresponding tearDown. --- @classmethod def setUpClass(cls): requires('gui') + cls.root = tk.Tk() + + @classmethod + def tearDownClass(cls): + cls.root.destroy() --- -All gui objects must be destroyed by the end of the test, perhaps in a tearDown -function. Support.requires('gui') returns true if it is either called in a main module (which never happens on buildbots) or if use_resources contains 'gui'. @@ -56,8 +63,9 @@ Since non-gui tests always run, but gui tests only sometimes, tests of non-gui operations should best avoid needing a gui. Methods that make incidental use of -tkinter variables and messageboxes can do this by using the mock classes in -idle_test/mock_tk.py. +tkinter (tk) variables and messageboxes can do this by using the mock classes in +idle_test/mock_tk.py. There is also a mock text that will handle some uses of the +tk Text widget. 3. Running Tests -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 28 22:41:16 2013 From: python-checkins at python.org (terry.reedy) Date: Sun, 28 Jul 2013 22:41:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Update_gui_sec?= =?utf-8?q?tion_of_idle_test_README=2E?= Message-ID: <3c3GCJ1zTZz7LlJ@mail.python.org> http://hg.python.org/cpython/rev/1dbcb0299088 changeset: 84893:1dbcb0299088 branch: 2.7 parent: 84881:2f5ee102f083 user: Terry Jan Reedy date: Sun Jul 28 16:39:44 2013 -0400 summary: Update gui section of idle test README. files: Lib/idlelib/idle_test/README.txt | 16 ++++++++++++---- 1 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/idle_test/README.txt b/Lib/idlelib/idle_test/README.txt --- a/Lib/idlelib/idle_test/README.txt +++ b/Lib/idlelib/idle_test/README.txt @@ -40,13 +40,20 @@ idle class. For the benefit of buildbot machines that do not have a graphics screen, gui tests must be 'guarded' by "requires('gui')" in a setUp function or method. This will typically be setUpClass. + +All gui objects must be destroyed by the end of the test, perhaps in a tearDown +function. Creating the Tk root directly in a setUp allows a reference to be saved +so it can be properly destroyed in the corresponding tearDown. --- @classmethod def setUpClass(cls): requires('gui') + cls.root = tk.Tk() + + @classmethod + def tearDownClass(cls): + cls.root.destroy() --- -All gui objects must be destroyed by the end of the test, perhaps in a tearDown -function. Support.requires('gui') returns true if it is either called in a main module (which never happens on buildbots) or if use_resources contains 'gui'. @@ -56,8 +63,9 @@ Since non-gui tests always run, but gui tests only sometimes, tests of non-gui operations should best avoid needing a gui. Methods that make incidental use of -tkinter variables and messageboxes can do this by using the mock classes in -idle_test/mock_tk.py. +tkinter (tk) variables and messageboxes can do this by using the mock classes in +idle_test/mock_tk.py. There is also a mock text that will handle some uses of the +tk Text widget. 3. Running Tests -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Mon Jul 29 04:46:39 2013 From: tjreedy at udel.edu (Terry Reedy) Date: Sun, 28 Jul 2013 22:46:39 -0400 Subject: [Python-checkins] cpython (3.3): Close #15415: Factor out temp dir helpers to test.support In-Reply-To: <3c33Cd2Mh8zQCG@mail.python.org> References: <3c33Cd2Mh8zQCG@mail.python.org> Message-ID: <51F5D78F.1090100@udel.edu> On 7/28/2013 8:25 AM, nick.coghlan wrote: > http://hg.python.org/cpython/rev/4f0034477ba9 > changeset: 84887:4f0034477ba9 > branch: 3.3 > parent: 84885:0b7ed24f7d33 > user: Nick Coghlan > date: Sun Jul 28 22:11:50 2013 +1000 > summary: > Close #15415: Factor out temp dir helpers to test.support The signature change (parameter deleted) broke all the windows buildbots, which were intermittently failing anyway. From solipsis at pitrou.net Mon Jul 29 05:48:36 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 29 Jul 2013 05:48:36 +0200 Subject: [Python-checkins] Daily reference leaks (4d08db5edbaa): sum=0 Message-ID: results for 4d08db5edbaa on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogUANAOZ', '-x'] From python-checkins at python.org Mon Jul 29 07:19:43 2013 From: python-checkins at python.org (nick.coghlan) Date: Mon, 29 Jul 2013 07:19:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Attempt_to_fix?= =?utf-8?q?_=2315415_on_Windows?= Message-ID: <3c3TjW0TztzRgM@mail.python.org> http://hg.python.org/cpython/rev/a76693942de3 changeset: 84894:a76693942de3 branch: 3.3 parent: 84891:70a4287a25b4 user: Nick Coghlan date: Mon Jul 29 15:18:09 2013 +1000 summary: Attempt to fix #15415 on Windows files: Lib/test/test_startfile.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -21,12 +21,12 @@ self.assertRaises(OSError, startfile, "nonexisting.vbs") def test_empty(self): - # Switch to an existing, but safe, working directory to let the - # cleanup code do its thing without permission errors. - with support.temp_cwd(path=path.dirname(sys.executable)): - empty = path.join(path.dirname(__file__), "empty.vbs") + # startfile is a little odd when it comes to handling absolute + # paths, so we briefly switch to the main test directory + # and use a relative path + with support.change_cwd(support.TEST_HOME): + empty = "empty.vbs" startfile(empty) - startfile(empty, "open") def test_main(): support.run_unittest(TestCase) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 29 07:19:44 2013 From: python-checkins at python.org (nick.coghlan) Date: Mon, 29 Jul 2013 07:19:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2315415_Windows_buildbot_change_from_3=2E3?= Message-ID: <3c3TjX2VBtzSRc@mail.python.org> http://hg.python.org/cpython/rev/b14308524cff changeset: 84895:b14308524cff parent: 84892:4d08db5edbaa parent: 84894:a76693942de3 user: Nick Coghlan date: Mon Jul 29 15:19:29 2013 +1000 summary: Merge #15415 Windows buildbot change from 3.3 files: Lib/test/test_startfile.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -21,12 +21,12 @@ self.assertRaises(OSError, startfile, "nonexisting.vbs") def test_empty(self): - # Switch to an existing, but safe, working directory to let the - # cleanup code do its thing without permission errors. - with support.temp_cwd(path=path.dirname(sys.executable)): - empty = path.join(path.dirname(__file__), "empty.vbs") + # startfile is a little odd when it comes to handling absolute + # paths, so we briefly switch to the main test directory + # and use a relative path + with support.change_cwd(support.TEST_HOME): + empty = "empty.vbs" startfile(empty) - startfile(empty, "open") def test_main(): support.run_unittest(TestCase) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 29 09:52:49 2013 From: python-checkins at python.org (nick.coghlan) Date: Mon, 29 Jul 2013 09:52:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Third_attempt_?= =?utf-8?q?to_fix_=2315415_on_Windows?= Message-ID: <3c3Y69155Vz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/403b038ff075 changeset: 84896:403b038ff075 branch: 3.3 parent: 84894:a76693942de3 user: Nick Coghlan date: Mon Jul 29 17:51:16 2013 +1000 summary: Third attempt to fix #15415 on Windows With help from jkloth on IRC, so it will hopefully work this time :) files: Lib/test/test_startfile.py | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -21,12 +21,14 @@ self.assertRaises(OSError, startfile, "nonexisting.vbs") def test_empty(self): - # startfile is a little odd when it comes to handling absolute - # paths, so we briefly switch to the main test directory - # and use a relative path - with support.change_cwd(support.TEST_HOME): - empty = "empty.vbs" + # We need to make sure the child process starts in a directory + # we're not about to delete. If we're running under -j, that + # means the test harness provided directory isn't a safe option. + # See http://bugs.python.org/issue15526 for more details + with support.change_cwd(path.dirname(sys.executable)): + empty = path.join(path.dirname(__file__), "empty.vbs") startfile(empty) + startfile(empty, "open") def test_main(): support.run_unittest(TestCase) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 29 09:52:50 2013 From: python-checkins at python.org (nick.coghlan) Date: Mon, 29 Jul 2013 09:52:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2315415_from_3=2E3_=28again=29?= Message-ID: <3c3Y6B3HCwz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/fa13a159f063 changeset: 84897:fa13a159f063 parent: 84895:b14308524cff parent: 84896:403b038ff075 user: Nick Coghlan date: Mon Jul 29 17:52:21 2013 +1000 summary: Merge #15415 from 3.3 (again) files: Lib/test/test_startfile.py | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -21,12 +21,14 @@ self.assertRaises(OSError, startfile, "nonexisting.vbs") def test_empty(self): - # startfile is a little odd when it comes to handling absolute - # paths, so we briefly switch to the main test directory - # and use a relative path - with support.change_cwd(support.TEST_HOME): - empty = "empty.vbs" + # We need to make sure the child process starts in a directory + # we're not about to delete. If we're running under -j, that + # means the test harness provided directory isn't a safe option. + # See http://bugs.python.org/issue15526 for more details + with support.change_cwd(path.dirname(sys.executable)): + empty = path.join(path.dirname(__file__), "empty.vbs") startfile(empty) + startfile(empty, "open") def test_main(): support.run_unittest(TestCase) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 29 16:37:13 2013 From: python-checkins at python.org (ronald.oussoren) Date: Mon, 29 Jul 2013 16:37:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Updated_the_PEP_447_text?= Message-ID: <3c3k4n3XbCz7LjQ@mail.python.org> http://hg.python.org/peps/rev/5d573095266d changeset: 5008:5d573095266d user: Ronald Oussoren date: Mon Jul 29 14:42:49 2013 +0200 summary: Updated the PEP 447 text * __locallookup__ is now required for all metatypes and is therefore defined on type. The method was optional to make it easier to detect if the attribute lookup cache can be used, but the same idea can be used when "type" implements tp_locallookup. * Added benchmarking results with PyBench. files: pep-0447.txt | 157 ++++++++++++++++++++++++++++++++++---- 1 files changed, 137 insertions(+), 20 deletions(-) diff --git a/pep-0447.txt b/pep-0447.txt --- a/pep-0447.txt +++ b/pep-0447.txt @@ -7,7 +7,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 12-Jun-2013 -Post-History: 2-Jul-2013, 15-Jul-2013 +Post-History: 2-Jul-2013, 15-Jul-2013, 29-Jul-2013 Abstract @@ -64,7 +64,6 @@ attribute resolution by both ``super.__getattribute__`` and ``object.__getattribute``:: class MetaType(type): - def __locallookup__(cls, name): try: return cls.__dict__[name] @@ -75,8 +74,8 @@ that is looked up. It should return the value of the attribute without invoking descriptors, or raise `AttributeError`_ when the name cannot be found. -The `type`_ class does not provide an implementation for ``__locallookup__``, primarily -to enable some optimizations in the Python implementation. +The `type`_ class provides a default implementation for ``__locallookup__``, that +looks up the name in the class dictionary. Example usage ............. @@ -85,7 +84,6 @@ versions of names:: class UpperCaseAccess (type): - def __locallookup__(cls, name): return cls.__dict__[name.upper()] @@ -114,18 +112,16 @@ and should not invoke descriptors. The method returns ``NULL`` without setting an exception when the *name* cannot be found, and returns a new reference otherwise (not a borrowed reference). +Use of this hook by the interpreter +----------------------------------- -Usage of this hook ------------------- - -The new method is optional and will not be defined on `type`_. Both ``super.__getattribute__`` -and ``object.__getattribute__``/`PyObject_GenericGetAttr`_ (through ``_PyType_Lookup``) will use the -the ``__locallookup__`` method when it is present in the meta type of a type on the MRO and will -continue to peek in the type's ``__dict__`` when the meta type does not have a ``__locallookup`` -method. +The new method is required for metatypes and as such is defined on `type_`. Both +``super.__getattribute__`` and ``object.__getattribute__``/`PyObject_GenericGetAttr`_ +(through ``_PyType_Lookup``) use the this ``__locallookup__`` method when walking +the MRO. Other changes to the implementation -................................... +----------------------------------- The change for `PyObject_GenericGetAttr`_ will be done by changing the private function ``_PyType_Lookup``. This currently returns a borrowed reference, but must return a new @@ -133,12 +129,134 @@ will be renamed to ``_PyType_LookupName``, this will cause compile-time errors for all out-of-tree users of this private API. -By making ``__locallookup_`` optional the implementation can continue to use the type attribute -lookup cache for types that don't have a metaclass with this new method, which should minimize the -performance impact of the change. +The attribute lookup cache in ``Objects/typeobject.c`` is disabled for classes that have a +metaclass that overrides ``__locallookup__``, because using the cache might not be valid +for such classes. -**TODO**: run pybench, an possibly the full speedtest, with and without this change and insert -the results. +Performance impact +------------------ + +The pybench output below compares an implementation of this PEP with the regular +source tree, both based on changeset a5681f50bae2, run on an idle machine an +Core i7 processor running Centos 6.4. + +Even though the machine was idle there were clear differences between runs, +I've seen difference in "minimum time" vary from -0.1% to +1.5%, with simular +(but slightly smaller) differences in the "average time" difference. + +.. :: + + ------------------------------------------------------------------------------- + PYBENCH 2.1 + ------------------------------------------------------------------------------- + * using CPython 3.4.0a0 (default, Jul 29 2013, 13:01:34) [GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] + * disabled garbage collection + * system check interval set to maximum: 2147483647 + * using timer: time.perf_counter + * timer: resolution=1e-09, implementation=clock_gettime(CLOCK_MONOTONIC) + + ------------------------------------------------------------------------------- + Benchmark: pep447.pybench + ------------------------------------------------------------------------------- + + Rounds: 10 + Warp: 10 + Timer: time.perf_counter + + Machine Details: + Platform ID: Linux-2.6.32-358.114.1.openstack.el6.x86_64-x86_64-with-centos-6.4-Final + Processor: x86_64 + + Python: + Implementation: CPython + Executable: /tmp/default-pep447/bin/python3 + Version: 3.4.0a0 + Compiler: GCC 4.4.7 20120313 (Red Hat 4.4.7-3) + Bits: 64bit + Build: Jul 29 2013 14:09:12 (#default) + Unicode: UCS4 + + + ------------------------------------------------------------------------------- + Comparing with: default.pybench + ------------------------------------------------------------------------------- + + Rounds: 10 + Warp: 10 + Timer: time.perf_counter + + Machine Details: + Platform ID: Linux-2.6.32-358.114.1.openstack.el6.x86_64-x86_64-with-centos-6.4-Final + Processor: x86_64 + + Python: + Implementation: CPython + Executable: /tmp/default/bin/python3 + Version: 3.4.0a0 + Compiler: GCC 4.4.7 20120313 (Red Hat 4.4.7-3) + Bits: 64bit + Build: Jul 29 2013 13:01:34 (#default) + Unicode: UCS4 + + + Test minimum run-time average run-time + this other diff this other diff + ------------------------------------------------------------------------------- + BuiltinFunctionCalls: 45ms 44ms +1.3% 45ms 44ms +1.3% + BuiltinMethodLookup: 26ms 27ms -2.4% 27ms 27ms -2.2% + CompareFloats: 33ms 34ms -0.7% 33ms 34ms -1.1% + CompareFloatsIntegers: 66ms 67ms -0.9% 66ms 67ms -0.8% + CompareIntegers: 51ms 50ms +0.9% 51ms 50ms +0.8% + CompareInternedStrings: 34ms 33ms +0.4% 34ms 34ms -0.4% + CompareLongs: 29ms 29ms -0.1% 29ms 29ms -0.0% + CompareStrings: 43ms 44ms -1.8% 44ms 44ms -1.8% + ComplexPythonFunctionCalls: 44ms 42ms +3.9% 44ms 42ms +4.1% + ConcatStrings: 33ms 33ms -0.4% 33ms 33ms -1.0% + CreateInstances: 47ms 48ms -2.9% 47ms 49ms -3.4% + CreateNewInstances: 35ms 36ms -2.5% 36ms 36ms -2.5% + CreateStringsWithConcat: 69ms 70ms -0.7% 69ms 70ms -0.9% + DictCreation: 52ms 50ms +3.1% 52ms 50ms +3.0% + DictWithFloatKeys: 40ms 44ms -10.1% 43ms 45ms -5.8% + DictWithIntegerKeys: 32ms 36ms -11.2% 35ms 37ms -4.6% + DictWithStringKeys: 29ms 34ms -15.7% 35ms 40ms -11.0% + ForLoops: 30ms 29ms +2.2% 30ms 29ms +2.2% + IfThenElse: 38ms 41ms -6.7% 38ms 41ms -6.9% + ListSlicing: 36ms 36ms -0.7% 36ms 37ms -1.3% + NestedForLoops: 43ms 45ms -3.1% 43ms 45ms -3.2% + NestedListComprehensions: 39ms 40ms -1.7% 39ms 40ms -2.1% + NormalClassAttribute: 86ms 82ms +5.1% 86ms 82ms +5.0% + NormalInstanceAttribute: 42ms 42ms +0.3% 42ms 42ms +0.0% + PythonFunctionCalls: 39ms 38ms +3.5% 39ms 38ms +2.8% + PythonMethodCalls: 51ms 49ms +3.0% 51ms 50ms +2.8% + Recursion: 67ms 68ms -1.4% 67ms 68ms -1.4% + SecondImport: 41ms 36ms +12.5% 41ms 36ms +12.6% + SecondPackageImport: 45ms 40ms +13.1% 45ms 40ms +13.2% + SecondSubmoduleImport: 92ms 95ms -2.4% 95ms 98ms -3.6% + SimpleComplexArithmetic: 28ms 28ms -0.1% 28ms 28ms -0.2% + SimpleDictManipulation: 57ms 57ms -1.0% 57ms 58ms -1.0% + SimpleFloatArithmetic: 29ms 28ms +4.7% 29ms 28ms +4.9% + SimpleIntFloatArithmetic: 37ms 41ms -8.5% 37ms 41ms -8.7% + SimpleIntegerArithmetic: 37ms 41ms -9.4% 37ms 42ms -10.2% + SimpleListComprehensions: 33ms 33ms -1.9% 33ms 34ms -2.9% + SimpleListManipulation: 28ms 30ms -4.3% 29ms 30ms -4.1% + SimpleLongArithmetic: 26ms 26ms +0.5% 26ms 26ms +0.5% + SmallLists: 40ms 40ms +0.1% 40ms 40ms +0.1% + SmallTuples: 46ms 47ms -2.4% 46ms 48ms -3.0% + SpecialClassAttribute: 126ms 120ms +4.7% 126ms 121ms +4.4% + SpecialInstanceAttribute: 42ms 42ms +0.6% 42ms 42ms +0.8% + StringMappings: 94ms 91ms +3.9% 94ms 91ms +3.8% + StringPredicates: 48ms 49ms -1.7% 48ms 49ms -2.1% + StringSlicing: 45ms 45ms +1.4% 46ms 45ms +1.5% + TryExcept: 23ms 22ms +4.9% 23ms 22ms +4.8% + TryFinally: 32ms 32ms -0.1% 32ms 32ms +0.1% + TryRaiseExcept: 17ms 17ms +0.9% 17ms 17ms +0.5% + TupleSlicing: 49ms 48ms +1.1% 49ms 49ms +1.0% + WithFinally: 48ms 47ms +2.3% 48ms 47ms +2.4% + WithRaiseExcept: 45ms 44ms +0.8% 45ms 45ms +0.5% + ------------------------------------------------------------------------------- + Totals: 2284ms 2287ms -0.1% 2306ms 2308ms -0.1% + + (this=pep447.pybench, other=default.pybench) Alternative proposals @@ -174,7 +292,6 @@ * `Issue 18181`_ contains a prototype implementation - Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 29 16:37:14 2013 From: python-checkins at python.org (ronald.oussoren) Date: Mon, 29 Jul 2013 16:37:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Include_results_for_a_2n3_run?= =?utf-8?q?_of_the_benchmark_suite=2E?= Message-ID: <3c3k4p5m0cz7LmC@mail.python.org> http://hg.python.org/peps/rev/4025217e41bc changeset: 5009:4025217e41bc user: Ronald Oussoren date: Mon Jul 29 16:36:47 2013 +0200 summary: Include results for a 2n3 run of the benchmark suite. files: pep-0447.txt | 94 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 94 insertions(+), 0 deletions(-) diff --git a/pep-0447.txt b/pep-0447.txt --- a/pep-0447.txt +++ b/pep-0447.txt @@ -259,6 +259,100 @@ (this=pep447.pybench, other=default.pybench) +A run of the benchmark suite (with option "-b 2n3") also seems to indicate that +the performance impact is minimal:: + + Report on Linux fangorn.local 2.6.32-358.114.1.openstack.el6.x86_64 #1 SMP Wed Jul 3 02:11:25 EDT 2013 x86_64 x86_64 + Total CPU cores: 8 + + ### call_method_slots ### + Min: 0.304120 -> 0.282791: 1.08x faster + Avg: 0.304394 -> 0.282906: 1.08x faster + Significant (t=2329.92) + Stddev: 0.00016 -> 0.00004: 4.1814x smaller + + ### call_simple ### + Min: 0.249268 -> 0.221175: 1.13x faster + Avg: 0.249789 -> 0.221387: 1.13x faster + Significant (t=2770.11) + Stddev: 0.00012 -> 0.00013: 1.1101x larger + + ### django_v2 ### + Min: 0.632590 -> 0.601519: 1.05x faster + Avg: 0.635085 -> 0.602653: 1.05x faster + Significant (t=321.32) + Stddev: 0.00087 -> 0.00051: 1.6933x smaller + + ### fannkuch ### + Min: 1.033181 -> 0.999779: 1.03x faster + Avg: 1.036457 -> 1.001840: 1.03x faster + Significant (t=260.31) + Stddev: 0.00113 -> 0.00070: 1.6112x smaller + + ### go ### + Min: 0.526714 -> 0.544428: 1.03x slower + Avg: 0.529649 -> 0.547626: 1.03x slower + Significant (t=-93.32) + Stddev: 0.00136 -> 0.00136: 1.0028x smaller + + ### iterative_count ### + Min: 0.109748 -> 0.116513: 1.06x slower + Avg: 0.109816 -> 0.117202: 1.07x slower + Significant (t=-357.08) + Stddev: 0.00008 -> 0.00019: 2.3664x larger + + ### json_dump_v2 ### + Min: 2.554462 -> 2.609141: 1.02x slower + Avg: 2.564472 -> 2.620013: 1.02x slower + Significant (t=-76.93) + Stddev: 0.00538 -> 0.00481: 1.1194x smaller + + ### meteor_contest ### + Min: 0.196336 -> 0.191925: 1.02x faster + Avg: 0.196878 -> 0.192698: 1.02x faster + Significant (t=61.86) + Stddev: 0.00053 -> 0.00041: 1.2925x smaller + + ### nbody ### + Min: 0.228039 -> 0.235551: 1.03x slower + Avg: 0.228857 -> 0.236052: 1.03x slower + Significant (t=-54.15) + Stddev: 0.00130 -> 0.00029: 4.4810x smaller + + ### pathlib ### + Min: 0.108501 -> 0.105339: 1.03x faster + Avg: 0.109084 -> 0.105619: 1.03x faster + Significant (t=311.08) + Stddev: 0.00022 -> 0.00011: 1.9314x smaller + + ### regex_effbot ### + Min: 0.057905 -> 0.056447: 1.03x faster + Avg: 0.058055 -> 0.056760: 1.02x faster + Significant (t=79.22) + Stddev: 0.00006 -> 0.00015: 2.7741x larger + + ### silent_logging ### + Min: 0.070810 -> 0.072436: 1.02x slower + Avg: 0.070899 -> 0.072609: 1.02x slower + Significant (t=-191.59) + Stddev: 0.00004 -> 0.00008: 2.2640x larger + + ### spectral_norm ### + Min: 0.290255 -> 0.299286: 1.03x slower + Avg: 0.290335 -> 0.299541: 1.03x slower + Significant (t=-572.10) + Stddev: 0.00005 -> 0.00015: 2.8547x larger + + ### threaded_count ### + Min: 0.107215 -> 0.115206: 1.07x slower + Avg: 0.107488 -> 0.115996: 1.08x slower + Significant (t=-109.39) + Stddev: 0.00016 -> 0.00076: 4.8665x larger + + The following not significant results are hidden, use -v to show them: + call_method, call_method_unknown, chaos, fastpickle, fastunpickle, float, formatted_logging, hexiom2, json_load, normal_startup, nqueens, pidigits, raytrace, regex_compile, regex_v8, richards, simple_logging, startup_nosite, telco, unpack_sequence. + + Alternative proposals --------------------- -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 29 18:50:00 2013 From: python-checkins at python.org (ronald.oussoren) Date: Mon, 29 Jul 2013 18:50:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_fix_markup_problem?= Message-ID: <3c3n205KJhz7Lp2@mail.python.org> http://hg.python.org/peps/rev/10bd48620fe8 changeset: 5010:10bd48620fe8 user: Ronald Oussoren date: Mon Jul 29 18:49:53 2013 +0200 summary: fix markup problem files: pep-0447.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0447.txt b/pep-0447.txt --- a/pep-0447.txt +++ b/pep-0447.txt @@ -144,7 +144,7 @@ I've seen difference in "minimum time" vary from -0.1% to +1.5%, with simular (but slightly smaller) differences in the "average time" difference. -.. :: +:: ------------------------------------------------------------------------------- PYBENCH 2.1 -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 29 22:02:13 2013 From: python-checkins at python.org (r.david.murray) Date: Mon, 29 Jul 2013 22:02:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4NTg0OiBtYWtl?= =?utf-8?q?_doctest_examples_in_email_documentation_pass=2E?= Message-ID: <3c3sHn3PVyzQq2@mail.python.org> http://hg.python.org/cpython/rev/ffc7ea3c04a5 changeset: 84898:ffc7ea3c04a5 branch: 3.3 parent: 84896:403b038ff075 user: R David Murray date: Mon Jul 29 15:49:58 2013 -0400 summary: #18584: make doctest examples in email documentation pass. With the exception of the 'as_string' call in the policy docs. That one is a separate issue. Note that when building the docs sphinx is complaining about .. testcleanup:: being an invalid directive. I don't know why this is, as I'm following the sphinx docs...but fortunately the action is to omit the text in the body, so the generated documentation is correct. files: Doc/library/email.iterators.rst | 16 ++++++- Doc/library/email.message.rst | 27 ++++++++---- Doc/library/email.policy.rst | 45 +++++++++++++++----- 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/Doc/library/email.iterators.rst b/Doc/library/email.iterators.rst --- a/Doc/library/email.iterators.rst +++ b/Doc/library/email.iterators.rst @@ -33,14 +33,22 @@ Thus, by default :func:`typed_subpart_iterator` returns each subpart that has a MIME type of :mimetype:`text/\*`. + The following function has been added as a useful debugging tool. It should *not* be considered part of the supported public interface for the package. - .. function:: _structure(msg, fp=None, level=0, include_default=False) Prints an indented representation of the content types of the message object - structure. For example:: + structure. For example: + + .. testsetup:: + + >>> import email + >>> from email.iterators import _structure + >>> somefile = open('Lib/test/test_email/data/msg_02.txt') + + .. doctest:: >>> msg = email.message_from_file(somefile) >>> _structure(msg) @@ -60,6 +68,10 @@ text/plain text/plain + .. testcleanup:: + + >>> somefile.close() + Optional *fp* is a file-like object to print the output to. It must be suitable for Python's :func:`print` function. *level* is used internally. *include_default*, if true, prints the default type as well. diff --git a/Doc/library/email.message.rst b/Doc/library/email.message.rst --- a/Doc/library/email.message.rst +++ b/Doc/library/email.message.rst @@ -513,16 +513,25 @@ iterator in a ``for`` loop; each iteration returns the next subpart. Here's an example that prints the MIME type of every part of a multipart - message structure:: + message structure: - >>> for part in msg.walk(): - ... print(part.get_content_type()) - multipart/report - text/plain - message/delivery-status - text/plain - text/plain - message/rfc822 + .. testsetup:: + + >>> from email import message_from_binary_file + >>> with open('Lib/test/test_email/data/msg_16.txt', 'rb') as f: + ... msg = message_from_binary_file(f) + + .. doctest:: + + >>> for part in msg.walk(): + ... print(part.get_content_type()) + multipart/report + text/plain + message/delivery-status + text/plain + text/plain + message/rfc822 + text/plain :class:`Message` objects can also optionally contain two instance attributes, which can be used when generating the plain text of a MIME message. diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -56,19 +56,42 @@ attributes values changed. As an example, the following code could be used to read an email message from a -file on disk and pass it to the system ``sendmail`` program on a Unix system:: +file on disk and pass it to the system ``sendmail`` program on a Unix system: - >>> from email import msg_from_binary_file +.. testsetup:: + + >>> from unittest import mock + >>> mocker = mock.patch('subprocess.Popen') + >>> m = mocker.start() + >>> proc = mock.MagicMock() + >>> m.return_value = proc + >>> proc.stdin.close.return_value = None + >>> mymsg = open('mymsg.txt', 'w') + >>> mymsg.write('To: abc at xyz.com\n\n') + 17 + >>> mymsg.flush() + +.. doctest:: + + >>> from email import message_from_binary_file >>> from email.generator import BytesGenerator + >>> from email import policy >>> from subprocess import Popen, PIPE - >>> with open('mymsg.txt', 'b') as f: - ... msg = msg_from_binary_file(f) - >>> p = Popen(['sendmail', msg['To'][0].address], stdin=PIPE) + >>> with open('mymsg.txt', 'rb') as f: + ... msg = message_from_binary_file(f, policy=policy.default) + >>> p = Popen(['sendmail', msg['To'].addresses[0]], stdin=PIPE) >>> g = BytesGenerator(p.stdin, policy=msg.policy.clone(linesep='\r\n')) >>> g.flatten(msg) >>> p.stdin.close() >>> rc = p.wait() +.. testcleanup:: + + >>> mymsg.close() + >>> mocker.stop() + >>> import os + >>> os.remove('mymsg.txt') + Here we are telling :class:`~email.generator.BytesGenerator` to use the RFC correct line separator characters when creating the binary string to feed into ``sendmail's`` ``stdin``, where the default policy would use ``\n`` line @@ -82,22 +105,22 @@ >>> import os >>> with open('converted.txt', 'wb') as f: - ... f.write(msg.as_string(policy=msg.policy.clone(linesep=os.linesep)) + ... f.write(msg.as_string(policy=msg.policy.clone(linesep=os.linesep))) Policy objects can also be combined using the addition operator, producing a policy object whose settings are a combination of the non-default values of the summed objects:: - >>> compat_SMTP = email.policy.clone(linesep='\r\n') - >>> compat_strict = email.policy.clone(raise_on_defect=True) + >>> compat_SMTP = policy.compat32.clone(linesep='\r\n') + >>> compat_strict = policy.compat32.clone(raise_on_defect=True) >>> compat_strict_SMTP = compat_SMTP + compat_strict This operation is not commutative; that is, the order in which the objects are added matters. To illustrate:: - >>> policy100 = compat32.clone(max_line_length=100) - >>> policy80 = compat32.clone(max_line_length=80) - >>> apolicy = policy100 + Policy80 + >>> policy100 = policy.compat32.clone(max_line_length=100) + >>> policy80 = policy.compat32.clone(max_line_length=80) + >>> apolicy = policy100 + policy80 >>> apolicy.max_line_length 80 >>> apolicy = policy80 + policy100 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 29 22:02:14 2013 From: python-checkins at python.org (r.david.murray) Date: Mon, 29 Jul 2013 22:02:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2318584=3A_make_doctest_examples_in_email_documen?= =?utf-8?q?tation_pass=2E?= Message-ID: <3c3sHp6dyWzSmF@mail.python.org> http://hg.python.org/cpython/rev/206685a4b19c changeset: 84899:206685a4b19c parent: 84897:fa13a159f063 parent: 84898:ffc7ea3c04a5 user: R David Murray date: Mon Jul 29 15:56:26 2013 -0400 summary: Merge #18584: make doctest examples in email documentation pass. files: Doc/library/email.iterators.rst | 16 ++++++- Doc/library/email.message.rst | 27 ++++++++---- Doc/library/email.policy.rst | 45 +++++++++++++++----- 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/Doc/library/email.iterators.rst b/Doc/library/email.iterators.rst --- a/Doc/library/email.iterators.rst +++ b/Doc/library/email.iterators.rst @@ -33,14 +33,22 @@ Thus, by default :func:`typed_subpart_iterator` returns each subpart that has a MIME type of :mimetype:`text/\*`. + The following function has been added as a useful debugging tool. It should *not* be considered part of the supported public interface for the package. - .. function:: _structure(msg, fp=None, level=0, include_default=False) Prints an indented representation of the content types of the message object - structure. For example:: + structure. For example: + + .. testsetup:: + + >>> import email + >>> from email.iterators import _structure + >>> somefile = open('Lib/test/test_email/data/msg_02.txt') + + .. doctest:: >>> msg = email.message_from_file(somefile) >>> _structure(msg) @@ -60,6 +68,10 @@ text/plain text/plain + .. testcleanup:: + + >>> somefile.close() + Optional *fp* is a file-like object to print the output to. It must be suitable for Python's :func:`print` function. *level* is used internally. *include_default*, if true, prints the default type as well. diff --git a/Doc/library/email.message.rst b/Doc/library/email.message.rst --- a/Doc/library/email.message.rst +++ b/Doc/library/email.message.rst @@ -513,16 +513,25 @@ iterator in a ``for`` loop; each iteration returns the next subpart. Here's an example that prints the MIME type of every part of a multipart - message structure:: + message structure: - >>> for part in msg.walk(): - ... print(part.get_content_type()) - multipart/report - text/plain - message/delivery-status - text/plain - text/plain - message/rfc822 + .. testsetup:: + + >>> from email import message_from_binary_file + >>> with open('Lib/test/test_email/data/msg_16.txt', 'rb') as f: + ... msg = message_from_binary_file(f) + + .. doctest:: + + >>> for part in msg.walk(): + ... print(part.get_content_type()) + multipart/report + text/plain + message/delivery-status + text/plain + text/plain + message/rfc822 + text/plain :class:`Message` objects can also optionally contain two instance attributes, which can be used when generating the plain text of a MIME message. diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -56,19 +56,42 @@ attributes values changed. As an example, the following code could be used to read an email message from a -file on disk and pass it to the system ``sendmail`` program on a Unix system:: +file on disk and pass it to the system ``sendmail`` program on a Unix system: - >>> from email import msg_from_binary_file +.. testsetup:: + + >>> from unittest import mock + >>> mocker = mock.patch('subprocess.Popen') + >>> m = mocker.start() + >>> proc = mock.MagicMock() + >>> m.return_value = proc + >>> proc.stdin.close.return_value = None + >>> mymsg = open('mymsg.txt', 'w') + >>> mymsg.write('To: abc at xyz.com\n\n') + 17 + >>> mymsg.flush() + +.. doctest:: + + >>> from email import message_from_binary_file >>> from email.generator import BytesGenerator + >>> from email import policy >>> from subprocess import Popen, PIPE - >>> with open('mymsg.txt', 'b') as f: - ... msg = msg_from_binary_file(f) - >>> p = Popen(['sendmail', msg['To'][0].address], stdin=PIPE) + >>> with open('mymsg.txt', 'rb') as f: + ... msg = message_from_binary_file(f, policy=policy.default) + >>> p = Popen(['sendmail', msg['To'].addresses[0]], stdin=PIPE) >>> g = BytesGenerator(p.stdin, policy=msg.policy.clone(linesep='\r\n')) >>> g.flatten(msg) >>> p.stdin.close() >>> rc = p.wait() +.. testcleanup:: + + >>> mymsg.close() + >>> mocker.stop() + >>> import os + >>> os.remove('mymsg.txt') + Here we are telling :class:`~email.generator.BytesGenerator` to use the RFC correct line separator characters when creating the binary string to feed into ``sendmail's`` ``stdin``, where the default policy would use ``\n`` line @@ -82,22 +105,22 @@ >>> import os >>> with open('converted.txt', 'wb') as f: - ... f.write(msg.as_string(policy=msg.policy.clone(linesep=os.linesep)) + ... f.write(msg.as_string(policy=msg.policy.clone(linesep=os.linesep))) Policy objects can also be combined using the addition operator, producing a policy object whose settings are a combination of the non-default values of the summed objects:: - >>> compat_SMTP = email.policy.clone(linesep='\r\n') - >>> compat_strict = email.policy.clone(raise_on_defect=True) + >>> compat_SMTP = policy.compat32.clone(linesep='\r\n') + >>> compat_strict = policy.compat32.clone(raise_on_defect=True) >>> compat_strict_SMTP = compat_SMTP + compat_strict This operation is not commutative; that is, the order in which the objects are added matters. To illustrate:: - >>> policy100 = compat32.clone(max_line_length=100) - >>> policy80 = compat32.clone(max_line_length=80) - >>> apolicy = policy100 + Policy80 + >>> policy100 = policy.compat32.clone(max_line_length=100) + >>> policy80 = policy.compat32.clone(max_line_length=80) + >>> apolicy = policy100 + policy80 >>> apolicy.max_line_length 80 >>> apolicy = policy80 + policy100 -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jul 30 05:48:06 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 30 Jul 2013 05:48:06 +0200 Subject: [Python-checkins] Daily reference leaks (206685a4b19c): sum=0 Message-ID: results for 206685a4b19c on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogWQ5aVs', '-x'] From python-checkins at python.org Tue Jul 30 07:37:57 2013 From: python-checkins at python.org (terry.reedy) Date: Tue, 30 Jul 2013 07:37:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Make_all_idle_?= =?utf-8?q?test_case_names_end_with_=27Test=27=2E?= Message-ID: <3c46451qN7z7LjS@mail.python.org> http://hg.python.org/cpython/rev/aa13693e3356 changeset: 84900:aa13693e3356 branch: 3.3 parent: 84898:ffc7ea3c04a5 user: Terry Jan Reedy date: Tue Jul 30 01:36:48 2013 -0400 summary: Make all idle test case names end with 'Test'. files: Lib/idlelib/idle_test/test_calltips.py | 2 +- Lib/idlelib/idle_test/test_config_name.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,7 +1,7 @@ import unittest import idlelib.CallTips as ct -class Test_get_entity(unittest.TestCase): +class Get_entityTest(unittest.TestCase): def test_bad_entity(self): self.assertIsNone(ct.get_entity('1/0')) def test_good_entity(self): diff --git a/Lib/idlelib/idle_test/test_config_name.py b/Lib/idlelib/idle_test/test_config_name.py --- a/Lib/idlelib/idle_test/test_config_name.py +++ b/Lib/idlelib/idle_test/test_config_name.py @@ -22,7 +22,7 @@ orig_mbox = name_dialog_module.tkMessageBox showerror = Mbox.showerror -class TestConfigName(unittest.TestCase): +class ConfigNameTest(unittest.TestCase): dialog = Dummy_name_dialog() @classmethod -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 07:37:58 2013 From: python-checkins at python.org (terry.reedy) Date: Tue, 30 Jul 2013 07:37:58 +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: <3c46463hNcz7LjV@mail.python.org> http://hg.python.org/cpython/rev/83b404da05e9 changeset: 84901:83b404da05e9 parent: 84899:206685a4b19c parent: 84900:aa13693e3356 user: Terry Jan Reedy date: Tue Jul 30 01:37:28 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/idle_test/test_calltips.py | 2 +- Lib/idlelib/idle_test/test_config_name.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,7 +1,7 @@ import unittest import idlelib.CallTips as ct -class Test_get_entity(unittest.TestCase): +class Get_entityTest(unittest.TestCase): def test_bad_entity(self): self.assertIsNone(ct.get_entity('1/0')) def test_good_entity(self): diff --git a/Lib/idlelib/idle_test/test_config_name.py b/Lib/idlelib/idle_test/test_config_name.py --- a/Lib/idlelib/idle_test/test_config_name.py +++ b/Lib/idlelib/idle_test/test_config_name.py @@ -22,7 +22,7 @@ orig_mbox = name_dialog_module.tkMessageBox showerror = Mbox.showerror -class TestConfigName(unittest.TestCase): +class ConfigNameTest(unittest.TestCase): dialog = Dummy_name_dialog() @classmethod -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 07:37:59 2013 From: python-checkins at python.org (terry.reedy) Date: Tue, 30 Jul 2013 07:37:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Make_all_idle_?= =?utf-8?q?test_case_names_end_with_=27Test=27=2E?= Message-ID: <3c46475YGzz7Lkm@mail.python.org> http://hg.python.org/cpython/rev/6e1dd1ce95b8 changeset: 84902:6e1dd1ce95b8 branch: 2.7 parent: 84893:1dbcb0299088 user: Terry Jan Reedy date: Tue Jul 30 01:37:36 2013 -0400 summary: Make all idle test case names end with 'Test'. files: Lib/idlelib/idle_test/test_calltips.py | 2 +- Lib/idlelib/idle_test/test_config_name.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -2,7 +2,7 @@ import idlelib.CallTips as ct CTi = ct.CallTips() -class Test_get_entity(unittest.TestCase): +class Get_entityTest(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): diff --git a/Lib/idlelib/idle_test/test_config_name.py b/Lib/idlelib/idle_test/test_config_name.py --- a/Lib/idlelib/idle_test/test_config_name.py +++ b/Lib/idlelib/idle_test/test_config_name.py @@ -22,7 +22,7 @@ orig_mbox = name_dialog_module.tkMessageBox showerror = Mbox.showerror -class TestConfigName(unittest.TestCase): +class ConfigNameTest(unittest.TestCase): dialog = Dummy_name_dialog() @classmethod -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 15:13:09 2013 From: python-checkins at python.org (eli.bendersky) Date: Tue, 30 Jul 2013 15:13:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTkz?= =?utf-8?q?=3A_fix_typo_in_comment?= Message-ID: <3c4J9K32N8z7LlX@mail.python.org> http://hg.python.org/cpython/rev/634d6307730d changeset: 84903:634d6307730d branch: 3.3 parent: 84900:aa13693e3356 user: Eli Bendersky date: Tue Jul 30 06:12:49 2013 -0700 summary: Issue #18593: fix typo in comment files: Lib/multiprocessing/heap.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -21,7 +21,7 @@ __all__ = ['BufferWrapper'] # -# Inheirtable class which wraps an mmap, and from which blocks can be allocated +# Inheritable class which wraps an mmap, and from which blocks can be allocated # if sys.platform == 'win32': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 15:13:10 2013 From: python-checkins at python.org (eli.bendersky) Date: Tue, 30 Jul 2013 15:13:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318593=3A_fix_typo_in_comment?= Message-ID: <3c4J9L4yLCz7Llq@mail.python.org> http://hg.python.org/cpython/rev/b805bace07c5 changeset: 84904:b805bace07c5 parent: 84901:83b404da05e9 parent: 84903:634d6307730d user: Eli Bendersky date: Tue Jul 30 06:13:01 2013 -0700 summary: Issue #18593: fix typo in comment files: Lib/multiprocessing/heap.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -21,7 +21,7 @@ __all__ = ['BufferWrapper'] # -# Inheirtable class which wraps an mmap, and from which blocks can be allocated +# Inheritable class which wraps an mmap, and from which blocks can be allocated # if sys.platform == 'win32': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 15:36:21 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 30 Jul 2013 15:36:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTk5?= =?utf-8?q?=3A_Fix_name_attribute_of_=5Fsha1=2Esha1=28=29_object=2E_It_now?= =?utf-8?q?_returns?= Message-ID: <3c4Jh53cY9z7Ljn@mail.python.org> http://hg.python.org/cpython/rev/c34c018a8390 changeset: 84905:c34c018a8390 branch: 3.3 parent: 84903:634d6307730d user: Christian Heimes date: Tue Jul 30 15:32:57 2013 +0200 summary: Issue #18599: Fix name attribute of _sha1.sha1() object. It now returns 'SHA1' instead of 'SHA'. files: Misc/NEWS | 3 +++ Modules/sha1module.c | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -57,6 +57,9 @@ Library ------- +- Issue #18599: Fix name attribute of _sha1.sha1() object. It now returns + 'SHA1' instead of 'SHA'. + - Issue #18561: Skip name in ctypes' _build_callargs() if name is NULL. - Issue #18559: Fix NULL pointer dereference error in _pickle module diff --git a/Modules/sha1module.c b/Modules/sha1module.c --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -415,7 +415,7 @@ static PyObject * SHA1_get_name(PyObject *self, void *closure) { - return PyUnicode_FromStringAndSize("SHA1", 3); + return PyUnicode_FromStringAndSize("SHA1", 4); } static PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 15:36:22 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 30 Jul 2013 15:36:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_more_tests?= =?utf-8?q?_for_hashlib_and_hash_object_attributes?= Message-ID: <3c4Jh66hzKz7Llr@mail.python.org> http://hg.python.org/cpython/rev/10501d5f07b8 changeset: 84906:10501d5f07b8 branch: 3.3 user: Christian Heimes date: Tue Jul 30 15:33:30 2013 +0200 summary: Add more tests for hashlib and hash object attributes files: Lib/test/test_hashlib.py | 75 +++++++++++++++++++++++---- 1 files changed, 62 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -96,10 +96,14 @@ super(HashLibTestCase, self).__init__(*args, **kwargs) + @property + def hash_constructors(self): + constructors = self.constructors_to_test.values() + return itertools.chain.from_iterable(constructors) + def test_hash_array(self): a = array.array("b", range(10)) - constructors = self.constructors_to_test.values() - for cons in itertools.chain.from_iterable(constructors): + for cons in self.hash_constructors: c = cons(a) c.hexdigest() @@ -136,39 +140,57 @@ self.assertRaises(TypeError, get_builtin_constructor, 3) def test_hexdigest(self): - for name in self.supported_hash_names: - h = hashlib.new(name) + for cons in self.hash_constructors: + h = cons() assert isinstance(h.digest(), bytes), name self.assertEqual(hexstr(h.digest()), h.hexdigest()) - def test_large_update(self): aas = b'a' * 128 bees = b'b' * 127 cees = b'c' * 126 + dees = b'd' * 2048 # HASHLIB_GIL_MINSIZE - for name in self.supported_hash_names: - m1 = hashlib.new(name) + for cons in self.hash_constructors: + m1 = cons() m1.update(aas) m1.update(bees) m1.update(cees) + m1.update(dees) - m2 = hashlib.new(name) - m2.update(aas + bees + cees) + m2 = cons() + m2.update(aas + bees + cees + dees) self.assertEqual(m1.digest(), m2.digest()) - def check(self, name, data, digest): + m3 = cons(aas + bees + cees + dees) + self.assertEqual(m1.digest(), m3.digest()) + + # verify copy() doesn't touch original + m4 = cons(aas + bees + cees) + m4_digest = m4.digest() + m4_copy = m4.copy() + m4_copy.update(dees) + self.assertEqual(m1.digest(), m4_copy.digest()) + self.assertEqual(m4.digest(), m4_digest) + + def check(self, name, data, hexdigest): + hexdigest = hexdigest.lower() constructors = self.constructors_to_test[name] # 2 is for hashlib.name(...) and hashlib.new(name, ...) self.assertGreaterEqual(len(constructors), 2) for hash_object_constructor in constructors: - computed = hash_object_constructor(data).hexdigest() + m = hash_object_constructor(data) + computed = m.hexdigest() self.assertEqual( - computed, digest, + computed, hexdigest, "Hash algorithm %s constructed using %s returned hexdigest" " %r for %d byte input data that should have hashed to %r." % (name, hash_object_constructor, - computed, len(data), digest)) + computed, len(data), hexdigest)) + computed = m.digest() + digest = bytes.fromhex(hexdigest) + self.assertEqual(computed, digest) + self.assertEqual(len(digest), m.digest_size) def check_no_unicode(self, algorithm_name): # Unicode objects are not allowed as input. @@ -184,6 +206,24 @@ self.check_no_unicode('sha384') self.check_no_unicode('sha512') + def check_blocksize_name(self, name, block_size=0, digest_size=0): + constructors = self.constructors_to_test[name] + for hash_object_constructor in constructors: + m = hash_object_constructor() + self.assertEqual(m.block_size, block_size) + self.assertEqual(m.digest_size, digest_size) + self.assertEqual(len(m.digest()), digest_size) + self.assertEqual(m.name.lower(), name.lower()) + self.assertIn(name.split("_")[0], repr(m).lower()) + + def test_blocksize_name(self): + self.check_blocksize_name('md5', 64, 16) + self.check_blocksize_name('sha1', 64, 20) + self.check_blocksize_name('sha224', 64, 28) + self.check_blocksize_name('sha256', 64, 32) + self.check_blocksize_name('sha384', 128, 48) + self.check_blocksize_name('sha512', 128, 64) + def test_case_md5_0(self): self.check('md5', b'', 'd41d8cd98f00b204e9800998ecf8427e') @@ -323,6 +363,15 @@ # for multithreaded operation (which is hardwired to 2048). gil_minsize = 2048 + for cons in self.hash_constructors: + m = cons() + m.update(b'1') + m.update(b'#' * gil_minsize) + m.update(b'1') + + m = cons(b'x' * gil_minsize) + m.update(b'1') + m = hashlib.md5() m.update(b'1') m.update(b'#' * gil_minsize) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 15:36:24 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 30 Jul 2013 15:36:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318599=3A_Fix_name_attribute_of_=5Fsha1=2Esha1?= =?utf-8?q?=28=29_object=2E_It_now_returns?= Message-ID: <3c4Jh82nprz7Llx@mail.python.org> http://hg.python.org/cpython/rev/5fbf23e947d8 changeset: 84907:5fbf23e947d8 parent: 84904:b805bace07c5 parent: 84906:10501d5f07b8 user: Christian Heimes date: Tue Jul 30 15:35:54 2013 +0200 summary: Issue #18599: Fix name attribute of _sha1.sha1() object. It now returns 'SHA1' instead of 'SHA'. Add more tests for hashlib and hash object attributes files: Lib/test/test_hashlib.py | 77 ++++++++++++++++++++++----- Misc/NEWS | 3 + Modules/sha1module.c | 2 +- 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -105,10 +105,14 @@ super(HashLibTestCase, self).__init__(*args, **kwargs) + @property + def hash_constructors(self): + constructors = self.constructors_to_test.values() + return itertools.chain.from_iterable(constructors) + def test_hash_array(self): a = array.array("b", range(10)) - constructors = self.constructors_to_test.values() - for cons in itertools.chain.from_iterable(constructors): + for cons in self.hash_constructors: c = cons(a) c.hexdigest() @@ -145,8 +149,8 @@ self.assertRaises(TypeError, get_builtin_constructor, 3) def test_hexdigest(self): - for name in self.supported_hash_names: - h = hashlib.new(name) + for cons in self.hash_constructors: + h = cons() assert isinstance(h.digest(), bytes), name self.assertEqual(hexstr(h.digest()), h.hexdigest()) @@ -155,30 +159,48 @@ aas = b'a' * 128 bees = b'b' * 127 cees = b'c' * 126 + dees = b'd' * 2048 # HASHLIB_GIL_MINSIZE - for name in self.supported_hash_names: - m1 = hashlib.new(name) + for cons in self.hash_constructors: + m1 = cons() m1.update(aas) m1.update(bees) m1.update(cees) + m1.update(dees) - m2 = hashlib.new(name) - m2.update(aas + bees + cees) + m2 = cons() + m2.update(aas + bees + cees + dees) self.assertEqual(m1.digest(), m2.digest()) - def check(self, name, data, digest): - digest = digest.lower() + m3 = cons(aas + bees + cees + dees) + self.assertEqual(m1.digest(), m3.digest()) + + # verify copy() doesn't touch original + m4 = cons(aas + bees + cees) + m4_digest = m4.digest() + m4_copy = m4.copy() + m4_copy.update(dees) + self.assertEqual(m1.digest(), m4_copy.digest()) + self.assertEqual(m4.digest(), m4_digest) + + def check(self, name, data, hexdigest): + hexdigest = hexdigest.lower() constructors = self.constructors_to_test[name] # 2 is for hashlib.name(...) and hashlib.new(name, ...) self.assertGreaterEqual(len(constructors), 2) for hash_object_constructor in constructors: - computed = hash_object_constructor(data).hexdigest() + m = hash_object_constructor(data) + computed = m.hexdigest() self.assertEqual( - computed, digest, + computed, hexdigest, "Hash algorithm %s constructed using %s returned hexdigest" " %r for %d byte input data that should have hashed to %r." % (name, hash_object_constructor, - computed, len(data), digest)) + computed, len(data), hexdigest)) + computed = m.digest() + digest = bytes.fromhex(hexdigest) + self.assertEqual(computed, digest) + self.assertEqual(len(digest), m.digest_size) def check_no_unicode(self, algorithm_name): # Unicode objects are not allowed as input. @@ -198,6 +220,29 @@ self.check_no_unicode('sha3_384') self.check_no_unicode('sha3_512') + def check_blocksize_name(self, name, block_size=0, digest_size=0): + constructors = self.constructors_to_test[name] + for hash_object_constructor in constructors: + m = hash_object_constructor() + self.assertEqual(m.block_size, block_size) + self.assertEqual(m.digest_size, digest_size) + self.assertEqual(len(m.digest()), digest_size) + self.assertEqual(m.name.lower(), name.lower()) + # split for sha3_512 / _sha3.sha3 object + self.assertIn(name.split("_")[0], repr(m).lower()) + + def test_blocksize_name(self): + self.check_blocksize_name('md5', 64, 16) + self.check_blocksize_name('sha1', 64, 20) + self.check_blocksize_name('sha224', 64, 28) + self.check_blocksize_name('sha256', 64, 32) + self.check_blocksize_name('sha384', 128, 48) + self.check_blocksize_name('sha512', 128, 64) + self.check_blocksize_name('sha3_224', NotImplemented, 28) + self.check_blocksize_name('sha3_256', NotImplemented, 32) + self.check_blocksize_name('sha3_384', NotImplemented, 48) + self.check_blocksize_name('sha3_512', NotImplemented, 64) + def test_case_md5_0(self): self.check('md5', b'', 'd41d8cd98f00b204e9800998ecf8427e') @@ -439,13 +484,13 @@ # for multithreaded operation (which is hardwired to 2048). gil_minsize = 2048 - for name in self.supported_hash_names: - m = hashlib.new(name) + for cons in self.hash_constructors: + m = cons() m.update(b'1') m.update(b'#' * gil_minsize) m.update(b'1') - m = hashlib.new(name, b'x' * gil_minsize) + m = cons(b'x' * gil_minsize) m.update(b'1') m = hashlib.md5() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -171,6 +171,9 @@ Library ------- +- Issue #18599: Fix name attribute of _sha1.sha1() object. It now returns + 'SHA1' instead of 'SHA'. + - Issue #13266: Added inspect.unwrap to easily unravel __wrapped__ chains (initial patch by Daniel Urban and Aaron Iles) diff --git a/Modules/sha1module.c b/Modules/sha1module.c --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -411,7 +411,7 @@ static PyObject * SHA1_get_name(PyObject *self, void *closure) { - return PyUnicode_FromStringAndSize("SHA1", 3); + return PyUnicode_FromStringAndSize("SHA1", 4); } static PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 15:44:31 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 30 Jul 2013 15:44:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_simple_tes?= =?utf-8?q?t_for_resource=2Egetpagesize=28=29?= Message-ID: <3c4JsW1Bnfz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/9bf89c909bd4 changeset: 84908:9bf89c909bd4 branch: 3.3 parent: 84906:10501d5f07b8 user: Christian Heimes date: Tue Jul 30 15:44:13 2013 +0200 summary: Add simple test for resource.getpagesize() files: Lib/test/test_resource.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_resource.py b/Lib/test/test_resource.py --- a/Lib/test/test_resource.py +++ b/Lib/test/test_resource.py @@ -124,6 +124,11 @@ resource.setrlimit(resource.RLIMIT_CPU, BadSequence()) + def test_pagesize(self): + pagesize = resource.getpagesize() + self.assertIsInstance(pagesize, int) + self.assertGreaterEqual(pagesize, 0) + def test_main(verbose=None): support.run_unittest(ResourceTest) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 15:44:32 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 30 Jul 2013 15:44:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Add_simple_test_for_resource=2Egetpagesize=28=29?= Message-ID: <3c4JsX3B8Nz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/f3183d60e6d0 changeset: 84909:f3183d60e6d0 parent: 84907:5fbf23e947d8 parent: 84908:9bf89c909bd4 user: Christian Heimes date: Tue Jul 30 15:44:24 2013 +0200 summary: Add simple test for resource.getpagesize() files: Lib/test/test_resource.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_resource.py b/Lib/test/test_resource.py --- a/Lib/test/test_resource.py +++ b/Lib/test/test_resource.py @@ -124,6 +124,11 @@ resource.setrlimit(resource.RLIMIT_CPU, BadSequence()) + def test_pagesize(self): + pagesize = resource.getpagesize() + self.assertIsInstance(pagesize, int) + self.assertGreaterEqual(pagesize, 0) + def test_main(verbose=None): support.run_unittest(ResourceTest) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 15:54:49 2013 From: python-checkins at python.org (christian.heimes) Date: Tue, 30 Jul 2013 15:54:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_simple_test_for_repr?= =?utf-8?b?KGxvY2sp?= Message-ID: <3c4K5P1Tlzz7LjS@mail.python.org> http://hg.python.org/cpython/rev/581da8df7ffd changeset: 84910:581da8df7ffd user: Christian Heimes date: Tue Jul 30 15:54:39 2013 +0200 summary: Add simple test for repr(lock) files: Lib/test/lock_tests.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -80,6 +80,11 @@ lock = self.locktype() del lock + def test_repr(self): + lock = self.locktype() + repr(lock) + del lock + def test_acquire_destroy(self): lock = self.locktype() lock.acquire() -- Repository URL: http://hg.python.org/cpython From rdmurray at bitdance.com Tue Jul 30 19:31:01 2013 From: rdmurray at bitdance.com (R. David Murray) Date: Tue, 30 Jul 2013 13:31:01 -0400 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NDQx?= =?utf-8?q?=3A_Make_test=2Esupport=2Erequires=28=27gui=27=29_skip_w?= =?utf-8?q?hen_it_should=2E?= In-Reply-To: <3c2jY31SQ0z7LjW@mail.python.org> References: <3c2jY31SQ0z7LjW@mail.python.org> Message-ID: <20130730173102.1195025007D@webabinitio.net> On Sun, 28 Jul 2013 01:09:43 +0200, terry.reedy wrote: > http://hg.python.org/cpython/rev/dd9941f5fcda > changeset: 84870:dd9941f5fcda > branch: 2.7 > parent: 84865:c0788ee86a65 > user: Terry Jan Reedy > date: Sun Jul 21 20:13:24 2013 -0400 > summary: > Issue #18441: Make test.support.requires('gui') skip when it should. > (Consolidating this check and various checks in tkinter files and moving them > to test.support and test.regrtest will be another issue.) > > files: > Lib/idlelib/idle_test/test_text.py | 5 +--- > Lib/test/test_idle.py | 20 ++++++++++++++--- > 2 files changed, 17 insertions(+), 8 deletions(-) > > > diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py > --- a/Lib/idlelib/idle_test/test_text.py > +++ b/Lib/idlelib/idle_test/test_text.py > @@ -216,10 +216,7 @@ > requires('gui') > from Tkinter import Tk, Text > cls.Text = Text > - try: > - cls.root = Tk() > - except TclError as msg: > - raise unittest.SkipTest('TclError: %s' % msg) > + cls.root = Tk() > > @classmethod > def tearDownClass(cls): > 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,9 +1,21 @@ > -# Skip test if _tkinter or _thread wasn't built or idlelib was deleted. > -from test.test_support import import_module > -import_module('Tkinter') > -import_module('threading') # imported by PyShell, imports _thread > +# Skip test if _thread or _tkinter wasn't built or idlelib was deleted. > +from test.test_support import import_module, use_resources > +import_module('threading') # imported by idlelib.PyShell, imports _thread > +tk = import_module('Tkinter') > idletest = import_module('idlelib.idle_test') > > +# If buildbot improperly sets gui resource (#18365, #18441), remove it > +# so requires('gui') tests are skipped while non-gui tests still run. > +if use_resources and 'gui' in use_resources: > + try: > + root = tk.Tk() > + root.destroy() > + except TclError: > + while True: > + use_resources.delete('gui') > + if 'gui' not in use_resources: > + break I believe that this logic is incorrect. If regrtest is run with "-u gui", given this code the skip message will be "requires gui resource"...but the caller specified the gui resource, which will make the skip message completely confusing. Instead, if it is true that 'gui' always means 'tk must work', then the _is_gui_available function should do the Tk() check. Currently as far as I can see it is indeed the case that requires('gui') always means tk must work. So, I believe that the correct fix is to move check_tk_availability to test.support, and call it from _is_gui_available. If we ever add another gui toolkit, we can deal with moving the tk check out into a separate 'tk' resource at that time. > + > # 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.) > > -- > 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 Tue Jul 30 20:01:06 2013 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 30 Jul 2013 20:01:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318112=3A_PEP_442_?= =?utf-8?q?implementation_=28safe_object_finalization=29=2E?= Message-ID: <3c4QYZ12mjz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/3f994367a979 changeset: 84911:3f994367a979 user: Antoine Pitrou date: Tue Jul 30 19:59:21 2013 +0200 summary: Issue #18112: PEP 442 implementation (safe object finalization). files: Doc/c-api/typeobj.rst | 49 ++ Doc/extending/newtypes.rst | 24 +- Doc/includes/typestruct.h | 7 + Doc/library/gc.rst | 27 +- Doc/library/weakref.rst | 21 +- Doc/reference/datamodel.rst | 10 +- Doc/whatsnew/3.4.rst | 15 + Include/object.h | 10 + Include/objimpl.h | 34 +- Lib/test/test_descr.py | 10 - Lib/test/test_finalization.py | 513 ++++++++++++++++++++++ Lib/test/test_gc.py | 18 +- Lib/test/test_generators.py | 53 ++ Lib/test/test_io.py | 45 +- Lib/test/test_sys.py | 4 +- Misc/NEWS | 2 + Modules/_io/bufferedio.c | 74 ++- Modules/_io/fileio.c | 24 +- Modules/_io/iobase.c | 92 ++- Modules/_io/textio.c | 37 +- Modules/_testcapimodule.c | 80 +++ Modules/gcmodule.c | 156 ++++-- Objects/genobject.c | 103 +--- Objects/object.c | 70 ++- Objects/typeobject.c | 97 ++-- 25 files changed, 1254 insertions(+), 321 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -465,6 +465,14 @@ :const:`Py_TPFLAGS_HAVE_VERSION_TAG`. + .. data:: Py_TPFLAGS_HAVE_FINALIZE + + This bit is set when the :attr:`tp_finalize` slot is present in the + type structure. + + .. versionadded:: 3.4 + + .. c:member:: char* PyTypeObject.tp_doc An optional pointer to a NUL-terminated C string giving the docstring for this @@ -968,6 +976,47 @@ This field is not inherited; it is calculated fresh by :c:func:`PyType_Ready`. +.. c:member:: destructor PyTypeObject.tp_finalize + + An optional pointer to an instance finalization function. Its signature is + :c:type:`destructor`:: + + void tp_finalize(PyObject *) + + If :attr:`tp_finalize` is set, the interpreter calls it once when + finalizing an instance. It is called either from the garbage + collector (if the instance is part of an isolated reference cycle) or + just before the object is deallocated. Either way, it is guaranteed + to be called before attempting to break reference cycles, ensuring + that it finds the object in a sane state. + + :attr:`tp_finalize` should not mutate the current exception status; + therefore, a recommended way to write a non-trivial finalizer is:: + + static void + local_finalize(PyObject *self) + { + PyObject *error_type, *error_value, *error_traceback; + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + /* ... */ + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + } + + For this field to be taken into account (even through inheritance), + you must also set the :const:`Py_TPFLAGS_HAVE_FINALIZE` flags bit. + + This field is inherited by subtypes. + + .. versionadded:: 3.4 + + .. seealso:: "Safe object finalization" (:pep:`442`) + + .. c:member:: PyObject* PyTypeObject.tp_cache Unused. Not inherited. Internal use only. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -157,7 +157,8 @@ Py_TPFLAGS_DEFAULT, /* tp_flags */ All types should include this constant in their flags. It enables all of the -members defined by the current version of Python. +members defined until at least Python 3.3. If you need further members, +you will need to OR the corresponding flags. We provide a doc string for the type in :attr:`tp_doc`. :: @@ -928,8 +929,9 @@ This function is called when the reference count of the instance of your type is reduced to zero and the Python interpreter wants to reclaim it. If your type -has memory to free or other clean-up to perform, put it here. The object itself -needs to be freed here as well. Here is an example of this function:: +has memory to free or other clean-up to perform, you can put it here. The +object itself needs to be freed here as well. Here is an example of this +function:: static void newdatatype_dealloc(newdatatypeobject * obj) @@ -981,6 +983,22 @@ Py_TYPE(obj)->tp_free((PyObject*)self); } +.. note:: + There are limitations to what you can safely do in a deallocator function. + First, if your type supports garbage collection (using :attr:`tp_traverse` + and/or :attr:`tp_clear`), some of the object's members can have been + cleared or finalized by the time :attr:`tp_dealloc` is called. Second, in + :attr:`tp_dealloc`, your object is in an unstable state: its reference + count is equal to zero. Any call to a non-trivial object or API (as in the + example above) might end up calling :attr:`tp_dealloc` again, causing a + double free and a crash. + + Starting with Python 3.4, it is recommended not to put any complex + finalization code in :attr:`tp_dealloc`, and instead use the new + :c:member:`~PyTypeObject.tp_finalize` type method. + + .. seealso:: + :pep:`442` explains the new finalization scheme. .. index:: single: string; object representation diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h --- a/Doc/includes/typestruct.h +++ b/Doc/includes/typestruct.h @@ -70,4 +70,11 @@ PyObject *tp_subclasses; PyObject *tp_weaklist; + destructor tp_del; + + /* Type attribute cache version tag. Added in version 2.6 */ + unsigned int tp_version_tag; + + destructor tp_finalize; + } PyTypeObject; diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -176,24 +176,13 @@ .. data:: garbage - A list of objects which the collector found to be unreachable but could not be - freed (uncollectable objects). By default, this list contains only objects with - :meth:`__del__` methods. Objects that have :meth:`__del__` methods and are - part of a reference cycle cause the entire reference cycle to be uncollectable, - including objects not necessarily in the cycle but reachable only from it. - Python doesn't collect such cycles automatically because, in general, it isn't - possible for Python to guess a safe order in which to run the :meth:`__del__` - methods. If you know a safe order, you can force the issue by examining the - *garbage* list, and explicitly breaking cycles due to your objects within the - list. Note that these objects are kept alive even so by virtue of being in the - *garbage* list, so they should be removed from *garbage* too. For example, - after breaking cycles, do ``del gc.garbage[:]`` to empty the list. It's - generally better to avoid the issue by not creating cycles containing objects - with :meth:`__del__` methods, and *garbage* can be examined in that case to - verify that no such cycles are being created. + A list of objects which the collector found to be unreachable but could + not be freed (uncollectable objects). Starting with Python 3.4, this + list should be empty most of the time, except when using instances of + C extension types with a non-NULL ``tp_del`` slot. - If :const:`DEBUG_SAVEALL` is set, then all unreachable objects will be added - to this list rather than freed. + If :const:`DEBUG_SAVEALL` is set, then all unreachable objects will be + added to this list rather than freed. .. versionchanged:: 3.2 If this list is non-empty at interpreter shutdown, a @@ -201,6 +190,10 @@ :const:`DEBUG_UNCOLLECTABLE` is set, in addition all uncollectable objects are printed. + .. versionchanged:: 3.4 + Following :pep:`442`, objects with a :meth:`__del__` method don't end + up in :attr:`gc.garbage` anymore. + .. data:: callbacks A list of callbacks that will be invoked by the garbage collector before and diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -529,22 +529,13 @@ def __del__(self): self.remove() -This solution has a couple of serious problems: +This solution has a serious problem: 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. -* 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:: +Using finalizers we can avoid this problem:: class TempDir: def __init__(self): diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1120,12 +1120,10 @@ ``sys.last_traceback`` keeps the stack frame alive). The first situation can only be remedied by explicitly breaking the cycles; the latter two situations can be resolved by storing ``None`` in ``sys.last_traceback``. - Circular references which are garbage are detected when the option cycle - detector is enabled (it's on by default), but can only be cleaned up if - there are no Python- level :meth:`__del__` methods involved. Refer to the - documentation for the :mod:`gc` module for more information about how - :meth:`__del__` methods are handled by the cycle detector, particularly - the description of the ``garbage`` value. + Circular references which are garbage are detected and cleaned up when + the cyclic garbage collector is enabled (it's on by default). Refer to the + documentation for the :mod:`gc` module for more information about this + topic. .. warning:: 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 @@ -119,6 +119,21 @@ Python memory allocators. +.. _pep-442: + +PEP 442: Safe object finalization +================================= + +This PEP removes the current limitations and quirks of object finalization. +With it, objects with :meth:`__del__` methods, as well as generators +with :keyword:`finally` clauses, can be finalized when they are part of a +reference cycle. + +.. seealso:: + + :pep:`442` - Safe object finalization + PEP written and implemented by Antoine Pitrou + Other Language Changes ====================== diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -408,6 +408,8 @@ /* Type attribute cache version tag. Added in version 2.6 */ unsigned int tp_version_tag; + destructor tp_finalize; + #ifdef COUNT_ALLOCS /* these must be last and never explicitly initialized */ Py_ssize_t tp_allocs; @@ -529,6 +531,8 @@ PyAPI_FUNC(int) PyCallable_Check(PyObject *); PyAPI_FUNC(void) PyObject_ClearWeakRefs(PyObject *); +PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *); +PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *); /* Same as PyObject_Generic{Get,Set}Attr, but passing the attributes dict as the last parameter. */ @@ -646,6 +650,12 @@ Py_TPFLAGS_HAVE_VERSION_TAG | \ 0) +/* NOTE: The following flags reuse lower bits (removed as part of the + * Python 3.0 transition). */ + +/* Type structure has tp_finalize member (3.4) */ +#define Py_TPFLAGS_HAVE_FINALIZE (1UL << 0) + #ifdef Py_LIMITED_API #define PyType_HasFeature(t,f) ((PyType_GetFlags(t) & (f)) != 0) #else diff --git a/Include/objimpl.h b/Include/objimpl.h --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -256,6 +256,30 @@ #define _Py_AS_GC(o) ((PyGC_Head *)(o)-1) +/* Bit 0 is set when tp_finalize is called */ +#define _PyGC_REFS_MASK_FINALIZED (1 << 0) +/* The (N-1) most significant bits contain the gc state / refcount */ +#define _PyGC_REFS_SHIFT (1) +#define _PyGC_REFS_MASK (((size_t) -1) << _PyGC_REFS_SHIFT) + +#define _PyGCHead_REFS(g) ((g)->gc.gc_refs >> _PyGC_REFS_SHIFT) +#define _PyGCHead_SET_REFS(g, v) do { \ + (g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK) \ + | (v << _PyGC_REFS_SHIFT); \ + } while (0) +#define _PyGCHead_DECREF(g) ((g)->gc.gc_refs -= 1 << _PyGC_REFS_SHIFT) + +#define _PyGCHead_FINALIZED(g) (((g)->gc.gc_refs & _PyGC_REFS_MASK_FINALIZED) != 0) +#define _PyGCHead_SET_FINALIZED(g, v) do { \ + (g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK_FINALIZED) \ + | (v != 0); \ + } while (0) + +#define _PyGC_FINALIZED(o) _PyGCHead_FINALIZED(_Py_AS_GC(o)) +#define _PyGC_SET_FINALIZED(o, v) _PyGCHead_SET_FINALIZED(_Py_AS_GC(o), v) + +#define _PyGC_REFS(o) _PyGCHead_REFS(_Py_AS_GC(o)) + #define _PyGC_REFS_UNTRACKED (-2) #define _PyGC_REFS_REACHABLE (-3) #define _PyGC_REFS_TENTATIVELY_UNREACHABLE (-4) @@ -264,9 +288,9 @@ * collector it must be safe to call the ob_traverse method. */ #define _PyObject_GC_TRACK(o) do { \ PyGC_Head *g = _Py_AS_GC(o); \ - if (g->gc.gc_refs != _PyGC_REFS_UNTRACKED) \ + if (_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED) \ Py_FatalError("GC object already tracked"); \ - g->gc.gc_refs = _PyGC_REFS_REACHABLE; \ + _PyGCHead_SET_REFS(g, _PyGC_REFS_REACHABLE); \ g->gc.gc_next = _PyGC_generation0; \ g->gc.gc_prev = _PyGC_generation0->gc.gc_prev; \ g->gc.gc_prev->gc.gc_next = g; \ @@ -279,8 +303,8 @@ */ #define _PyObject_GC_UNTRACK(o) do { \ PyGC_Head *g = _Py_AS_GC(o); \ - assert(g->gc.gc_refs != _PyGC_REFS_UNTRACKED); \ - g->gc.gc_refs = _PyGC_REFS_UNTRACKED; \ + assert(_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED); \ + _PyGCHead_SET_REFS(g, _PyGC_REFS_UNTRACKED); \ g->gc.gc_prev->gc.gc_next = g->gc.gc_next; \ g->gc.gc_next->gc.gc_prev = g->gc.gc_prev; \ g->gc.gc_next = NULL; \ @@ -288,7 +312,7 @@ /* True if the object is currently tracked by the GC. */ #define _PyObject_GC_IS_TRACKED(o) \ - ((_Py_AS_GC(o))->gc.gc_refs != _PyGC_REFS_UNTRACKED) + (_PyGC_REFS(o) != _PyGC_REFS_UNTRACKED) /* True if the object may be tracked by the GC in the future, or already is. This can be useful to implement some optimizations. */ 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 @@ -3736,18 +3736,8 @@ # bug). del c - # If that didn't blow up, it's also interesting to see whether clearing - # the last container slot works: that will attempt to delete c again, - # which will cause c to get appended back to the container again - # "during" the del. (On non-CPython implementations, however, __del__ - # is typically not called again.) support.gc_collect() self.assertEqual(len(C.container), 1) - del C.container[-1] - if support.check_impl_detail(): - support.gc_collect() - self.assertEqual(len(C.container), 1) - self.assertEqual(C.container[-1].attr, 42) # Make c mortal again, so that the test framework with -l doesn't report # it as a leak. diff --git a/Lib/test/test_finalization.py b/Lib/test/test_finalization.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_finalization.py @@ -0,0 +1,513 @@ +""" +Tests for object finalization semantics, as outlined in PEP 442. +""" + +import contextlib +import gc +import unittest +import weakref + +import _testcapi +from test import support + + +class NonGCSimpleBase: + """ + The base class for all the objects under test, equipped with various + testing features. + """ + + survivors = [] + del_calls = [] + tp_del_calls = [] + errors = [] + + _cleaning = False + + __slots__ = () + + @classmethod + def _cleanup(cls): + cls.survivors.clear() + cls.errors.clear() + gc.garbage.clear() + gc.collect() + cls.del_calls.clear() + cls.tp_del_calls.clear() + + @classmethod + @contextlib.contextmanager + def test(cls): + """ + A context manager to use around all finalization tests. + """ + with support.disable_gc(): + cls.del_calls.clear() + cls.tp_del_calls.clear() + NonGCSimpleBase._cleaning = False + try: + yield + if cls.errors: + raise cls.errors[0] + finally: + NonGCSimpleBase._cleaning = True + cls._cleanup() + + def check_sanity(self): + """ + Check the object is sane (non-broken). + """ + + def __del__(self): + """ + PEP 442 finalizer. Record that this was called, check the + object is in a sane state, and invoke a side effect. + """ + try: + if not self._cleaning: + self.del_calls.append(id(self)) + self.check_sanity() + self.side_effect() + except Exception as e: + self.errors.append(e) + + def side_effect(self): + """ + A side effect called on destruction. + """ + + +class SimpleBase(NonGCSimpleBase): + + def __init__(self): + self.id_ = id(self) + + def check_sanity(self): + assert self.id_ == id(self) + + +class NonGC(NonGCSimpleBase): + __slots__ = () + +class NonGCResurrector(NonGCSimpleBase): + __slots__ = () + + def side_effect(self): + """ + Resurrect self by storing self in a class-wide list. + """ + self.survivors.append(self) + +class Simple(SimpleBase): + pass + +class SimpleResurrector(NonGCResurrector, SimpleBase): + pass + + +class TestBase: + + def setUp(self): + self.old_garbage = gc.garbage[:] + gc.garbage[:] = [] + + def tearDown(self): + # None of the tests here should put anything in gc.garbage + try: + self.assertEqual(gc.garbage, []) + finally: + del self.old_garbage + gc.collect() + + def assert_del_calls(self, ids): + self.assertEqual(sorted(SimpleBase.del_calls), sorted(ids)) + + def assert_tp_del_calls(self, ids): + self.assertEqual(sorted(SimpleBase.tp_del_calls), sorted(ids)) + + def assert_survivors(self, ids): + self.assertEqual(sorted(id(x) for x in SimpleBase.survivors), sorted(ids)) + + def assert_garbage(self, ids): + self.assertEqual(sorted(id(x) for x in gc.garbage), sorted(ids)) + + def clear_survivors(self): + SimpleBase.survivors.clear() + + +class SimpleFinalizationTest(TestBase, unittest.TestCase): + """ + Test finalization without refcycles. + """ + + def test_simple(self): + with SimpleBase.test(): + s = Simple() + ids = [id(s)] + wr = weakref.ref(s) + del s + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + self.assertIs(wr(), None) + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + + def test_simple_resurrect(self): + with SimpleBase.test(): + s = SimpleResurrector() + ids = [id(s)] + wr = weakref.ref(s) + del s + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors(ids) + self.assertIsNot(wr(), None) + self.clear_survivors() + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + self.assertIs(wr(), None) + + def test_non_gc(self): + with SimpleBase.test(): + s = NonGC() + self.assertFalse(gc.is_tracked(s)) + ids = [id(s)] + del s + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + + def test_non_gc_resurrect(self): + with SimpleBase.test(): + s = NonGCResurrector() + self.assertFalse(gc.is_tracked(s)) + ids = [id(s)] + del s + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors(ids) + self.clear_survivors() + gc.collect() + self.assert_del_calls(ids * 2) + self.assert_survivors(ids) + + +class SelfCycleBase: + + def __init__(self): + super().__init__() + self.ref = self + + def check_sanity(self): + super().check_sanity() + assert self.ref is self + +class SimpleSelfCycle(SelfCycleBase, Simple): + pass + +class SelfCycleResurrector(SelfCycleBase, SimpleResurrector): + pass + +class SuicidalSelfCycle(SelfCycleBase, Simple): + + def side_effect(self): + """ + Explicitly break the reference cycle. + """ + self.ref = None + + +class SelfCycleFinalizationTest(TestBase, unittest.TestCase): + """ + Test finalization of an object having a single cyclic reference to + itself. + """ + + def test_simple(self): + with SimpleBase.test(): + s = SimpleSelfCycle() + ids = [id(s)] + wr = weakref.ref(s) + del s + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + self.assertIs(wr(), None) + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + + def test_simple_resurrect(self): + # Test that __del__ can resurrect the object being finalized. + with SimpleBase.test(): + s = SelfCycleResurrector() + ids = [id(s)] + wr = weakref.ref(s) + del s + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors(ids) + # XXX is this desirable? + self.assertIs(wr(), None) + # When trying to destroy the object a second time, __del__ + # isn't called anymore (and the object isn't resurrected). + self.clear_survivors() + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + self.assertIs(wr(), None) + + def test_simple_suicide(self): + # Test the GC is able to deal with an object that kills its last + # reference during __del__. + with SimpleBase.test(): + s = SuicidalSelfCycle() + ids = [id(s)] + wr = weakref.ref(s) + del s + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + self.assertIs(wr(), None) + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + self.assertIs(wr(), None) + + +class ChainedBase: + + def chain(self, left): + self.suicided = False + self.left = left + left.right = self + + def check_sanity(self): + super().check_sanity() + if self.suicided: + assert self.left is None + assert self.right is None + else: + left = self.left + if left.suicided: + assert left.right is None + else: + assert left.right is self + right = self.right + if right.suicided: + assert right.left is None + else: + assert right.left is self + +class SimpleChained(ChainedBase, Simple): + pass + +class ChainedResurrector(ChainedBase, SimpleResurrector): + pass + +class SuicidalChained(ChainedBase, Simple): + + def side_effect(self): + """ + Explicitly break the reference cycle. + """ + self.suicided = True + self.left = None + self.right = None + + +class CycleChainFinalizationTest(TestBase, unittest.TestCase): + """ + Test finalization of a cyclic chain. These tests are similar in + spirit to the self-cycle tests above, but the collectable object + graph isn't trivial anymore. + """ + + def build_chain(self, classes): + nodes = [cls() for cls in classes] + for i in range(len(nodes)): + nodes[i].chain(nodes[i-1]) + return nodes + + def check_non_resurrecting_chain(self, classes): + N = len(classes) + with SimpleBase.test(): + nodes = self.build_chain(classes) + ids = [id(s) for s in nodes] + wrs = [weakref.ref(s) for s in nodes] + del nodes + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + self.assertEqual([wr() for wr in wrs], [None] * N) + gc.collect() + self.assert_del_calls(ids) + + def check_resurrecting_chain(self, classes): + N = len(classes) + with SimpleBase.test(): + nodes = self.build_chain(classes) + N = len(nodes) + ids = [id(s) for s in nodes] + survivor_ids = [id(s) for s in nodes if isinstance(s, SimpleResurrector)] + wrs = [weakref.ref(s) for s in nodes] + del nodes + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors(survivor_ids) + # XXX desirable? + self.assertEqual([wr() for wr in wrs], [None] * N) + self.clear_survivors() + gc.collect() + self.assert_del_calls(ids) + self.assert_survivors([]) + + def test_homogenous(self): + self.check_non_resurrecting_chain([SimpleChained] * 3) + + def test_homogenous_resurrect(self): + self.check_resurrecting_chain([ChainedResurrector] * 3) + + def test_homogenous_suicidal(self): + self.check_non_resurrecting_chain([SuicidalChained] * 3) + + def test_heterogenous_suicidal_one(self): + self.check_non_resurrecting_chain([SuicidalChained, SimpleChained] * 2) + + def test_heterogenous_suicidal_two(self): + self.check_non_resurrecting_chain( + [SuicidalChained] * 2 + [SimpleChained] * 2) + + def test_heterogenous_resurrect_one(self): + self.check_resurrecting_chain([ChainedResurrector, SimpleChained] * 2) + + def test_heterogenous_resurrect_two(self): + self.check_resurrecting_chain( + [ChainedResurrector, SimpleChained, SuicidalChained] * 2) + + def test_heterogenous_resurrect_three(self): + self.check_resurrecting_chain( + [ChainedResurrector] * 2 + [SimpleChained] * 2 + [SuicidalChained] * 2) + + +# NOTE: the tp_del slot isn't automatically inherited, so we have to call +# with_tp_del() for each instantiated class. + +class LegacyBase(SimpleBase): + + def __del__(self): + try: + # Do not invoke side_effect here, since we are now exercising + # the tp_del slot. + if not self._cleaning: + self.del_calls.append(id(self)) + self.check_sanity() + except Exception as e: + self.errors.append(e) + + def __tp_del__(self): + """ + Legacy (pre-PEP 442) finalizer, mapped to a tp_del slot. + """ + try: + if not self._cleaning: + self.tp_del_calls.append(id(self)) + self.check_sanity() + self.side_effect() + except Exception as e: + self.errors.append(e) + + at _testcapi.with_tp_del +class Legacy(LegacyBase): + pass + + at _testcapi.with_tp_del +class LegacyResurrector(LegacyBase): + + def side_effect(self): + """ + Resurrect self by storing self in a class-wide list. + """ + self.survivors.append(self) + + at _testcapi.with_tp_del +class LegacySelfCycle(SelfCycleBase, LegacyBase): + pass + + +class LegacyFinalizationTest(TestBase, unittest.TestCase): + """ + Test finalization of objects with a tp_del. + """ + + def tearDown(self): + # These tests need to clean up a bit more, since they create + # uncollectable objects. + gc.garbage.clear() + gc.collect() + super().tearDown() + + def test_legacy(self): + with SimpleBase.test(): + s = Legacy() + ids = [id(s)] + wr = weakref.ref(s) + del s + gc.collect() + self.assert_del_calls(ids) + self.assert_tp_del_calls(ids) + self.assert_survivors([]) + self.assertIs(wr(), None) + gc.collect() + self.assert_del_calls(ids) + self.assert_tp_del_calls(ids) + + def test_legacy_resurrect(self): + with SimpleBase.test(): + s = LegacyResurrector() + ids = [id(s)] + wr = weakref.ref(s) + del s + gc.collect() + self.assert_del_calls(ids) + self.assert_tp_del_calls(ids) + self.assert_survivors(ids) + # weakrefs are cleared before tp_del is called. + self.assertIs(wr(), None) + self.clear_survivors() + gc.collect() + self.assert_del_calls(ids) + self.assert_tp_del_calls(ids * 2) + self.assert_survivors(ids) + self.assertIs(wr(), None) + + def test_legacy_self_cycle(self): + # Self-cycles with legacy finalizers end up in gc.garbage. + with SimpleBase.test(): + s = LegacySelfCycle() + ids = [id(s)] + wr = weakref.ref(s) + del s + gc.collect() + self.assert_del_calls([]) + self.assert_tp_del_calls([]) + self.assert_survivors([]) + self.assert_garbage(ids) + self.assertIsNot(wr(), None) + # Break the cycle to allow collection + gc.garbage[0].ref = None + self.assert_garbage([]) + self.assertIs(wr(), None) + + +def test_main(): + support.run_unittest(__name__) + +if __name__ == "__main__": + test_main() 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,3 +1,4 @@ +import _testcapi import unittest from test.support import (verbose, refcount_test, run_unittest, strip_python_stderr) @@ -40,6 +41,7 @@ # gc collects it. self.wr = weakref.ref(C1055820(666), it_happened) + at _testcapi.with_tp_del class Uncollectable(object): """Create a reference cycle with multiple __del__ methods. @@ -52,7 +54,7 @@ self.partner = Uncollectable(partner=self) else: self.partner = partner - def __del__(self): + def __tp_del__(self): pass ### Tests @@ -141,11 +143,12 @@ del a self.assertNotEqual(gc.collect(), 0) - def test_finalizer(self): + def test_legacy_finalizer(self): # A() is uncollectable if it is part of a cycle, make sure it shows up # in gc.garbage. + @_testcapi.with_tp_del class A: - def __del__(self): pass + def __tp_del__(self): pass class B: pass a = A() @@ -165,11 +168,12 @@ self.fail("didn't find obj in garbage (finalizer)") gc.garbage.remove(obj) - def test_finalizer_newclass(self): + def test_legacy_finalizer_newclass(self): # A() is uncollectable if it is part of a cycle, make sure it shows up # in gc.garbage. + @_testcapi.with_tp_del class A(object): - def __del__(self): pass + def __tp_del__(self): pass class B(object): pass a = A() @@ -570,12 +574,14 @@ import subprocess code = """if 1: import gc + import _testcapi + @_testcapi.with_tp_del class X: def __init__(self, name): self.name = name def __repr__(self): return "" %% self.name - def __del__(self): + def __tp_del__(self): pass x = X('first') 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_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1072,12 +1072,13 @@ def test_garbage_collection(self): # C BufferedReader objects are collected. # The Python version has __del__, so it ends into gc.garbage instead - rawio = self.FileIO(support.TESTFN, "w+b") - f = self.tp(rawio) - f.f = f - wr = weakref.ref(f) - del f - support.gc_collect() + with support.check_warnings(('', ResourceWarning)): + rawio = self.FileIO(support.TESTFN, "w+b") + f = self.tp(rawio) + f.f = f + wr = weakref.ref(f) + del f + support.gc_collect() self.assertTrue(wr() is None, wr) def test_args_error(self): @@ -1366,13 +1367,14 @@ # C BufferedWriter objects are collected, and collecting them flushes # all data to disk. # The Python version has __del__, so it ends into gc.garbage instead - rawio = self.FileIO(support.TESTFN, "w+b") - f = self.tp(rawio) - f.write(b"123xxx") - f.x = f - wr = weakref.ref(f) - del f - support.gc_collect() + with support.check_warnings(('', ResourceWarning)): + rawio = self.FileIO(support.TESTFN, "w+b") + f = self.tp(rawio) + f.write(b"123xxx") + f.x = f + wr = weakref.ref(f) + del f + support.gc_collect() self.assertTrue(wr() is None, wr) with self.open(support.TESTFN, "rb") as f: self.assertEqual(f.read(), b"123xxx") @@ -2607,14 +2609,15 @@ # C TextIOWrapper objects are collected, and collecting them flushes # all data to disk. # The Python version has __del__, so it ends in gc.garbage instead. - rawio = io.FileIO(support.TESTFN, "wb") - b = self.BufferedWriter(rawio) - t = self.TextIOWrapper(b, encoding="ascii") - t.write("456def") - t.x = t - wr = weakref.ref(t) - del t - support.gc_collect() + with support.check_warnings(('', ResourceWarning)): + rawio = io.FileIO(support.TESTFN, "wb") + b = self.BufferedWriter(rawio) + t = self.TextIOWrapper(b, encoding="ascii") + t.write("456def") + t.x = t + wr = weakref.ref(t) + del t + support.gc_collect() self.assertTrue(wr() is None, wr) with self.open(support.TESTFN, "rb") as f: self.assertEqual(f.read(), b"456def") 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 @@ -864,11 +864,11 @@ check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - s = vsize('P2n15Pl4Pn9Pn11PI') + s = vsize('P2n15Pl4Pn9Pn11PIP') check(int, s) # (PyTypeObject + PyNumberMethods + PyMappingMethods + # PySequenceMethods + PyBufferProcs + 4P) - s = vsize('P2n15Pl4Pn9Pn11PI') + struct.calcsize('34P 3P 10P 2P 4P') + s = vsize('P2n15Pl4Pn9Pn11PIP') + struct.calcsize('34P 3P 10P 2P 4P') # Separate block for PyDictKeysObject with 4 entries s += struct.calcsize("2nPn") + 4*struct.calcsize("n2P") # class diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #18112: PEP 442 implementation (safe object finalization). + - Issue #18552: Check return value of PyArena_AddPyObject() in obj2ast_object(). diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -190,7 +190,8 @@ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferediobase_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -209,6 +210,16 @@ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -220,7 +231,7 @@ int detached; int readable; int writable; - int deallocating; + char finalizing; /* True if this is a vanilla Buffered object (rather than a user derived class) *and* the raw stream is a vanilla FileIO object. */ @@ -384,8 +395,8 @@ static void buffered_dealloc(buffered *self) { - self->deallocating = 1; - if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0) + self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) return; _PyObject_GC_UNTRACK(self); self->ok = 0; @@ -428,8 +439,6 @@ static int buffered_clear(buffered *self) { - if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0) - return -1; self->ok = 0; Py_CLEAR(self->raw); Py_CLEAR(self->dict); @@ -508,7 +517,7 @@ goto end; } - if (self->deallocating) { + if (self->finalizing) { PyObject *r = buffered_dealloc_warn(self, (PyObject *) self); if (r) Py_DECREF(r); @@ -1749,6 +1758,7 @@ static PyMemberDef bufferedreader_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, {NULL} }; @@ -1781,7 +1791,7 @@ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferedreader_doc, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ @@ -1800,6 +1810,16 @@ (initproc)bufferedreader_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -2130,6 +2150,7 @@ static PyMemberDef bufferedwriter_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, {NULL} }; @@ -2162,7 +2183,7 @@ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferedwriter_doc, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ @@ -2181,6 +2202,16 @@ (initproc)bufferedwriter_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -2416,7 +2447,7 @@ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ bufferedrwpair_doc, /* tp_doc */ (traverseproc)bufferedrwpair_traverse, /* tp_traverse */ (inquiry)bufferedrwpair_clear, /* tp_clear */ @@ -2435,6 +2466,16 @@ (initproc)bufferedrwpair_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -2522,6 +2563,7 @@ static PyMemberDef bufferedrandom_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, {NULL} }; @@ -2554,7 +2596,7 @@ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferedrandom_doc, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ @@ -2573,4 +2615,14 @@ (initproc)bufferedrandom_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -51,7 +51,7 @@ unsigned int writable : 1; signed int seekable : 2; /* -1 means unknown */ unsigned int closefd : 1; - unsigned int deallocating: 1; + char finalizing; PyObject *weakreflist; PyObject *dict; } fileio; @@ -128,7 +128,7 @@ self->fd = -1; Py_RETURN_NONE; } - if (self->deallocating) { + if (self->finalizing) { PyObject *r = fileio_dealloc_warn(self, (PyObject *) self); if (r) Py_DECREF(r); @@ -447,7 +447,7 @@ static void fileio_dealloc(fileio *self) { - self->deallocating = 1; + self->finalizing = 1; if (_PyIOBase_finalize((PyObject *) self) < 0) return; _PyObject_GC_UNTRACK(self); @@ -1182,6 +1182,11 @@ {NULL}, }; +static PyMemberDef fileio_members[] = { + {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0}, + {NULL} +}; + PyTypeObject PyFileIO_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_io.FileIO", @@ -1203,7 +1208,7 @@ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ fileio_doc, /* tp_doc */ (traverseproc)fileio_traverse, /* tp_traverse */ (inquiry)fileio_clear, /* tp_clear */ @@ -1212,7 +1217,7 @@ 0, /* tp_iter */ 0, /* tp_iternext */ fileio_methods, /* tp_methods */ - 0, /* tp_members */ + fileio_members, /* tp_members */ fileio_getsetlist, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ @@ -1223,4 +1228,13 @@ PyType_GenericAlloc, /* tp_alloc */ fileio_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -196,21 +196,17 @@ /* Finalization and garbage collection support */ -int -_PyIOBase_finalize(PyObject *self) +static void +iobase_finalize(PyObject *self) { PyObject *res; - PyObject *tp, *v, *tb; - int closed = 1; - int is_zombie; + PyObject *error_type, *error_value, *error_traceback; + int closed; + _Py_IDENTIFIER(_finalizing); - /* If _PyIOBase_finalize() is called from a destructor, we need to - resurrect the object as calling close() can invoke arbitrary code. */ - is_zombie = (Py_REFCNT(self) == 0); - if (is_zombie) { - ++Py_REFCNT(self); - } - PyErr_Fetch(&tp, &v, &tb); + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + /* If `closed` doesn't exist or can't be evaluated as bool, then the object is probably in an unusable state, so ignore. */ res = PyObject_GetAttr(self, _PyIO_str_closed); @@ -223,6 +219,10 @@ PyErr_Clear(); } if (closed == 0) { + /* Signal close() that it was called as part of the object + finalization process. */ + if (_PyObject_SetAttrId(self, &PyId__finalizing, Py_True)) + PyErr_Clear(); res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_close, NULL); /* Silencing I/O errors is bad, but printing spurious tracebacks is @@ -233,31 +233,25 @@ else Py_DECREF(res); } - PyErr_Restore(tp, v, tb); - if (is_zombie) { - if (--Py_REFCNT(self) != 0) { - /* The object lives again. The following code is taken from - slot_tp_del in typeobject.c. */ - Py_ssize_t refcnt = Py_REFCNT(self); - _Py_NewReference(self); - Py_REFCNT(self) = 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 - return -1; - } + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); +} + +int +_PyIOBase_finalize(PyObject *self) +{ + int is_zombie; + + /* If _PyIOBase_finalize() is called from a destructor, we need to + resurrect the object as calling close() can invoke arbitrary code. */ + is_zombie = (Py_REFCNT(self) == 0); + if (is_zombie) + return PyObject_CallFinalizerFromDealloc(self); + else { + PyObject_CallFinalizer(self); + return 0; } - return 0; } static int @@ -270,8 +264,6 @@ static int iobase_clear(iobase *self) { - if (_PyIOBase_finalize((PyObject *) self) < 0) - return -1; Py_CLEAR(self->dict); return 0; } @@ -741,7 +733,7 @@ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ iobase_doc, /* tp_doc */ (traverseproc)iobase_traverse, /* tp_traverse */ (inquiry)iobase_clear, /* tp_clear */ @@ -760,6 +752,16 @@ 0, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + (destructor)iobase_finalize, /* tp_finalize */ }; @@ -905,7 +907,7 @@ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ rawiobase_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -924,4 +926,14 @@ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -173,7 +173,8 @@ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ textiobase_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -192,6 +193,16 @@ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -691,7 +702,7 @@ char seekable; char has_read1; char telling; - char deallocating; + char finalizing; /* Specialized encoding func (see below) */ encodefunc_t encodefunc; /* Whether or not it's the start of the stream */ @@ -1112,8 +1123,6 @@ static int _textiowrapper_clear(textio *self) { - if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0) - return -1; self->ok = 0; Py_CLEAR(self->buffer); Py_CLEAR(self->encoding); @@ -1131,9 +1140,10 @@ static void textiowrapper_dealloc(textio *self) { - self->deallocating = 1; - if (_textiowrapper_clear(self) < 0) + self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) return; + _textiowrapper_clear(self); _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *)self); @@ -2573,7 +2583,7 @@ } else { PyObject *exc = NULL, *val, *tb; - if (self->deallocating) { + if (self->finalizing) { res = _PyObject_CallMethodId(self->buffer, &PyId__dealloc_warn, "O", self); if (res) Py_DECREF(res); @@ -2734,6 +2744,7 @@ {"encoding", T_OBJECT, offsetof(textio, encoding), READONLY}, {"buffer", T_OBJECT, offsetof(textio, buffer), READONLY}, {"line_buffering", T_BOOL, offsetof(textio, line_buffering), READONLY}, + {"_finalizing", T_BOOL, offsetof(textio, finalizing), 0}, {NULL} }; @@ -2770,7 +2781,7 @@ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ textiowrapper_doc, /* tp_doc */ (traverseproc)textiowrapper_traverse, /* tp_traverse */ (inquiry)textiowrapper_clear, /* tp_clear */ @@ -2789,4 +2800,14 @@ (initproc)textiowrapper_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2491,6 +2491,85 @@ return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); } +static void +slot_tp_del(PyObject *self) +{ + _Py_IDENTIFIER(__tp_del__); + PyObject *del, *res; + PyObject *error_type, *error_value, *error_traceback; + + /* 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); + + /* Execute __del__ method, if any. */ + del = _PyObject_LookupSpecial(self, &PyId___tp_del__); + if (del != NULL) { + res = PyEval_CallObject(del, NULL); + if (res == NULL) + PyErr_WriteUnraisable(del); + else + Py_DECREF(res); + Py_DECREF(del); + } + + /* 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 */ + + /* __del__ 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 +} + +static PyObject * +with_tp_del(PyObject *self, PyObject *args) +{ + PyObject *obj; + PyTypeObject *tp; + + if (!PyArg_ParseTuple(args, "O:with_tp_del", &obj)) + return NULL; + tp = (PyTypeObject *) obj; + if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { + PyErr_Format(PyExc_TypeError, + "heap type expected, got %R", obj); + return NULL; + } + tp->tp_del = slot_tp_del; + Py_INCREF(obj); + return obj; +} + static PyObject * _test_incref(PyObject *ob) { @@ -2789,6 +2868,7 @@ {"pytime_object_to_time_t", test_pytime_object_to_time_t, METH_VARARGS}, {"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS}, {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, + {"with_tp_del", with_tp_del, METH_VARARGS}, {"test_pymem", (PyCFunction)test_pymem_alloc0, METH_NOARGS}, {"test_pymem_alloc0", diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -223,10 +223,10 @@ #define GC_REACHABLE _PyGC_REFS_REACHABLE #define GC_TENTATIVELY_UNREACHABLE _PyGC_REFS_TENTATIVELY_UNREACHABLE -#define IS_TRACKED(o) ((AS_GC(o))->gc.gc_refs != GC_UNTRACKED) -#define IS_REACHABLE(o) ((AS_GC(o))->gc.gc_refs == GC_REACHABLE) +#define IS_TRACKED(o) (_PyGC_REFS(o) != GC_UNTRACKED) +#define IS_REACHABLE(o) (_PyGC_REFS(o) == GC_REACHABLE) #define IS_TENTATIVELY_UNREACHABLE(o) ( \ - (AS_GC(o))->gc.gc_refs == GC_TENTATIVELY_UNREACHABLE) + _PyGC_REFS(o) == GC_TENTATIVELY_UNREACHABLE) /*** list functions ***/ @@ -341,8 +341,8 @@ { PyGC_Head *gc = containers->gc.gc_next; for (; gc != containers; gc = gc->gc.gc_next) { - assert(gc->gc.gc_refs == GC_REACHABLE); - gc->gc.gc_refs = Py_REFCNT(FROM_GC(gc)); + assert(_PyGCHead_REFS(gc) == GC_REACHABLE); + _PyGCHead_SET_REFS(gc, Py_REFCNT(FROM_GC(gc))); /* Python's cyclic gc should never see an incoming refcount * of 0: if something decref'ed to 0, it should have been * deallocated immediately at that time. @@ -361,7 +361,7 @@ * so serious that maybe this should be a release-build * check instead of an assert? */ - assert(gc->gc.gc_refs != 0); + assert(_PyGCHead_REFS(gc) != 0); } } @@ -376,9 +376,9 @@ * generation being collected, which can be recognized * because only they have positive gc_refs. */ - assert(gc->gc.gc_refs != 0); /* else refcount was too small */ - if (gc->gc.gc_refs > 0) - gc->gc.gc_refs--; + assert(_PyGCHead_REFS(gc) != 0); /* else refcount was too small */ + if (_PyGCHead_REFS(gc) > 0) + _PyGCHead_DECREF(gc); } return 0; } @@ -407,7 +407,7 @@ { if (PyObject_IS_GC(op)) { PyGC_Head *gc = AS_GC(op); - const Py_ssize_t gc_refs = gc->gc.gc_refs; + const Py_ssize_t gc_refs = _PyGCHead_REFS(gc); if (gc_refs == 0) { /* This is in move_unreachable's 'young' list, but @@ -415,7 +415,7 @@ * we need to do is tell move_unreachable that it's * reachable. */ - gc->gc.gc_refs = 1; + _PyGCHead_SET_REFS(gc, 1); } else if (gc_refs == GC_TENTATIVELY_UNREACHABLE) { /* This had gc_refs = 0 when move_unreachable got @@ -425,7 +425,7 @@ * again. */ gc_list_move(gc, reachable); - gc->gc.gc_refs = 1; + _PyGCHead_SET_REFS(gc, 1); } /* Else there's nothing to do. * If gc_refs > 0, it must be in move_unreachable's 'young' @@ -469,7 +469,7 @@ while (gc != young) { PyGC_Head *next; - if (gc->gc.gc_refs) { + if (_PyGCHead_REFS(gc)) { /* gc is definitely reachable from outside the * original 'young'. Mark it as such, and traverse * its pointers to find any other objects that may @@ -480,8 +480,8 @@ */ PyObject *op = FROM_GC(gc); traverseproc traverse = Py_TYPE(op)->tp_traverse; - assert(gc->gc.gc_refs > 0); - gc->gc.gc_refs = GC_REACHABLE; + assert(_PyGCHead_REFS(gc) > 0); + _PyGCHead_SET_REFS(gc, GC_REACHABLE); (void) traverse(op, (visitproc)visit_reachable, (void *)young); @@ -500,7 +500,7 @@ */ next = gc->gc.gc_next; gc_list_move(gc, unreachable); - gc->gc.gc_refs = GC_TENTATIVELY_UNREACHABLE; + _PyGCHead_SET_REFS(gc, GC_TENTATIVELY_UNREACHABLE); } gc = next; } @@ -520,22 +520,19 @@ } } -/* Return true if object has a finalization method. */ +/* Return true if object has a pre-PEP 442 finalization method. */ static int -has_finalizer(PyObject *op) +has_legacy_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`. +/* Move the objects in unreachable with tp_del slots into `finalizers`. * Objects moved into `finalizers` have gc_refs set to GC_REACHABLE; the * objects remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE. */ static void -move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) +move_legacy_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) { PyGC_Head *gc; PyGC_Head *next; @@ -549,14 +546,14 @@ assert(IS_TENTATIVELY_UNREACHABLE(op)); next = gc->gc.gc_next; - if (has_finalizer(op)) { + if (has_legacy_finalizer(op)) { gc_list_move(gc, finalizers); - gc->gc.gc_refs = GC_REACHABLE; + _PyGCHead_SET_REFS(gc, GC_REACHABLE); } } } -/* A traversal callback for move_finalizer_reachable. */ +/* A traversal callback for move_legacy_finalizer_reachable. */ static int visit_move(PyObject *op, PyGC_Head *tolist) { @@ -564,7 +561,7 @@ if (IS_TENTATIVELY_UNREACHABLE(op)) { PyGC_Head *gc = AS_GC(op); gc_list_move(gc, tolist); - gc->gc.gc_refs = GC_REACHABLE; + _PyGCHead_SET_REFS(gc, GC_REACHABLE); } } return 0; @@ -574,7 +571,7 @@ * into finalizers set. */ static void -move_finalizer_reachable(PyGC_Head *finalizers) +move_legacy_finalizer_reachable(PyGC_Head *finalizers) { traverseproc traverse; PyGC_Head *gc = finalizers->gc.gc_next; @@ -747,7 +744,7 @@ msg, Py_TYPE(op)->tp_name, op); } -/* Handle uncollectable garbage (cycles with finalizers, and stuff reachable +/* Handle uncollectable garbage (cycles with tp_del slots, and stuff reachable * only from such cycles). * If DEBUG_SAVEALL, all objects in finalizers are appended to the module * garbage list (a Python list), else only the objects in finalizers with @@ -757,7 +754,7 @@ * The finalizers list is made empty on a successful return. */ static int -handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old) +handle_legacy_finalizers(PyGC_Head *finalizers, PyGC_Head *old) { PyGC_Head *gc = finalizers->gc.gc_next; @@ -769,7 +766,7 @@ for (; gc != finalizers; gc = gc->gc.gc_next) { PyObject *op = FROM_GC(gc); - if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) { + if ((debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) { if (PyList_Append(garbage, op) < 0) return -1; } @@ -779,6 +776,62 @@ return 0; } +static void +finalize_garbage(PyGC_Head *collectable, PyGC_Head *old) +{ + destructor finalize; + PyGC_Head *gc = collectable->gc.gc_next; + + for (; gc != collectable; gc = gc->gc.gc_next) { + PyObject *op = FROM_GC(gc); + + if (!_PyGCHead_FINALIZED(gc) && + PyType_HasFeature(Py_TYPE(op), Py_TPFLAGS_HAVE_FINALIZE) && + (finalize = Py_TYPE(op)->tp_finalize) != NULL) { + _PyGCHead_SET_FINALIZED(gc, 1); + Py_INCREF(op); + finalize(op); + if (Py_REFCNT(op) == 1) { + /* op will be destroyed */ + gc = gc->gc.gc_prev; + } + Py_DECREF(op); + } + } +} + +/* Walk the collectable list and check that they are really unreachable + from the outside (some objects could have been resurrected by a + finalizer). */ +static int +check_garbage(PyGC_Head *collectable) +{ + PyGC_Head *gc; + for (gc = collectable->gc.gc_next; gc != collectable; + gc = gc->gc.gc_next) { + _PyGCHead_SET_REFS(gc, Py_REFCNT(FROM_GC(gc))); + assert(_PyGCHead_REFS(gc) != 0); + } + subtract_refs(collectable); + for (gc = collectable->gc.gc_next; gc != collectable; + gc = gc->gc.gc_next) { + assert(_PyGCHead_REFS(gc) >= 0); + if (_PyGCHead_REFS(gc) != 0) + return -1; + } + return 0; +} + +static void +revive_garbage(PyGC_Head *collectable) +{ + PyGC_Head *gc; + for (gc = collectable->gc.gc_next; gc != collectable; + gc = gc->gc.gc_next) { + _PyGCHead_SET_REFS(gc, GC_REACHABLE); + } +} + /* Break reference cycles by clearing the containers involved. This is * tricky business as the lists can be changing and we don't know which * objects may be freed. It is possible I screwed something up here. @@ -792,7 +845,6 @@ PyGC_Head *gc = collectable->gc.gc_next; PyObject *op = FROM_GC(gc); - assert(IS_TENTATIVELY_UNREACHABLE(op)); if (debug & DEBUG_SAVEALL) { PyList_Append(garbage, op); } @@ -806,7 +858,7 @@ if (collectable->gc.gc_next == gc) { /* object is still alive, move it, it may die later */ gc_list_move(gc, old); - gc->gc.gc_refs = GC_REACHABLE; + _PyGCHead_SET_REFS(gc, GC_REACHABLE); } } } @@ -929,19 +981,15 @@ } /* All objects in unreachable are trash, but objects reachable from - * finalizers can't safely be deleted. Python programmers should take - * care not to create such things. For Python, finalizers means - * instance objects with __del__ methods. Weakrefs with callbacks - * can also call arbitrary Python code but they will be dealt with by - * handle_weakrefs(). + * legacy finalizers (e.g. tp_del) can't safely be deleted. */ gc_list_init(&finalizers); - move_finalizers(&unreachable, &finalizers); - /* finalizers contains the unreachable objects with a finalizer; + move_legacy_finalizers(&unreachable, &finalizers); + /* finalizers contains the unreachable objects with a legacy finalizer; * unreachable objects reachable *from* those are also uncollectable, * and we move those into the finalizers list too. */ - move_finalizer_reachable(&finalizers); + move_legacy_finalizer_reachable(&finalizers); /* Collect statistics on collectable objects found and print * debugging information. @@ -957,11 +1005,20 @@ /* Clear weakrefs and invoke callbacks as necessary. */ m += handle_weakrefs(&unreachable, old); - /* Call tp_clear on objects in the unreachable set. This will cause - * the reference cycles to be broken. It may also cause some objects - * in finalizers to be freed. - */ - delete_garbage(&unreachable, old); + /* Call tp_finalize on objects which have one. */ + finalize_garbage(&unreachable, old); + + if (check_garbage(&unreachable)) { + revive_garbage(&unreachable); + gc_list_merge(&unreachable, old); + } + else { + /* Call tp_clear on objects in the unreachable set. This will cause + * the reference cycles to be broken. It may also cause some objects + * in finalizers to be freed. + */ + delete_garbage(&unreachable, old); + } /* Collect statistics on uncollectable objects found and print * debugging information. */ @@ -992,7 +1049,7 @@ * reachable list of garbage. The programmer has to deal with * this if they insist on creating this type of structure. */ - (void)handle_finalizers(&finalizers, old); + (void)handle_legacy_finalizers(&finalizers, old); /* Clear free list only during the collection of the highest * generation */ @@ -1662,7 +1719,8 @@ sizeof(PyGC_Head) + basicsize); if (g == NULL) return PyErr_NoMemory(); - g->gc.gc_refs = GC_UNTRACKED; + g->gc.gc_refs = 0; + _PyGCHead_SET_REFS(g, GC_UNTRACKED); generations[0].count++; /* number of allocated GC objects */ if (generations[0].count > generations[0].threshold && enabled && diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -16,6 +16,31 @@ } static void +gen_finalize(PyObject *self) +{ + PyGenObject *gen = (PyGenObject *)self; + PyObject *res; + PyObject *error_type, *error_value, *error_traceback; + + if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL) + /* Generator isn't paused, so no need to close */ + return; + + /* 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); +} + +static void gen_dealloc(PyGenObject *gen) { PyObject *self = (PyObject *) gen; @@ -27,12 +52,8 @@ _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. :( */ - } + if (PyObject_CallFinalizerFromDealloc(self)) + return; /* resurrected. :( */ _PyObject_GC_UNTRACK(self); Py_CLEAR(gen->gi_frame); @@ -40,7 +61,6 @@ PyObject_GC_Del(gen); } - static PyObject * gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) { @@ -222,68 +242,6 @@ return NULL; } -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\ @@ -517,7 +475,8 @@ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ 0, /* tp_doc */ (traverseproc)gen_traverse, /* tp_traverse */ 0, /* tp_clear */ @@ -544,7 +503,9 @@ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ - gen_del, /* tp_del */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + gen_finalize, /* tp_finalize */ }; PyObject * diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -255,6 +255,72 @@ return PyObject_INIT_VAR(op, tp, nitems); } +void +PyObject_CallFinalizer(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + + /* The former could happen on heaptypes created from the C API, e.g. + PyType_FromSpec(). */ + if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_FINALIZE) || + tp->tp_finalize == NULL) + return; + /* tp_finalize should only be called once. */ + if (PyType_IS_GC(tp) && _PyGC_FINALIZED(self)) + return; + + tp->tp_finalize(self); + if (PyType_IS_GC(tp)) + _PyGC_SET_FINALIZED(self, 1); +} + +int +PyObject_CallFinalizerFromDealloc(PyObject *self) +{ + Py_ssize_t refcnt; + + /* Temporarily resurrect the object. */ + if (self->ob_refcnt != 0) { + Py_FatalError("PyObject_CallFinalizerFromDealloc called on " + "object with a non-zero refcount"); + } + self->ob_refcnt = 1; + + PyObject_CallFinalizer(self); + + /* 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 0; /* this is the normal path out */ + + /* tp_finalize resurrected it! Make it look like the original Py_DECREF + * never happened. + */ + refcnt = self->ob_refcnt; + _Py_NewReference(self); + self->ob_refcnt = refcnt; + + if (PyType_IS_GC(Py_TYPE(self))) { + assert(_PyGC_REFS(self) != _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 + return -1; +} + int PyObject_Print(PyObject *op, FILE *fp, int flags) { @@ -1981,7 +2047,7 @@ _PyTrash_deposit_object(PyObject *op) { assert(PyObject_IS_GC(op)); - assert(_Py_AS_GC(op)->gc.gc_refs == _PyGC_REFS_UNTRACKED); + assert(_PyGC_REFS(op) == _PyGC_REFS_UNTRACKED); assert(op->ob_refcnt == 0); _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *)_PyTrash_delete_later; _PyTrash_delete_later = op; @@ -1993,7 +2059,7 @@ { PyThreadState *tstate = PyThreadState_GET(); assert(PyObject_IS_GC(op)); - assert(_Py_AS_GC(op)->gc.gc_refs == _PyGC_REFS_UNTRACKED); + assert(_PyGC_REFS(op) == _PyGC_REFS_UNTRACKED); assert(op->ob_refcnt == 0); _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *) tstate->trash_delete_later; tstate->trash_delete_later = op; diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -921,6 +921,7 @@ PyTypeObject *type, *base; destructor basedealloc; PyThreadState *tstate = PyThreadState_GET(); + int has_finalizer; /* Extract the type; we expect it to be a heap type */ type = Py_TYPE(self); @@ -936,6 +937,10 @@ clear_slots(), or DECREF the dict, or clear weakrefs. */ /* Maybe call finalizer; exit early if resurrected */ + if (type->tp_finalize) { + if (PyObject_CallFinalizerFromDealloc(self) < 0) + return; + } if (type->tp_del) { type->tp_del(self); if (self->ob_refcnt > 0) @@ -987,25 +992,36 @@ assert(base); } + has_finalizer = type->tp_finalize || type->tp_del; + + /* Maybe call finalizer; exit early if resurrected */ + if (has_finalizer) + _PyObject_GC_TRACK(self); + + if (type->tp_finalize) { + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + /* Resurrected */ + goto endlabel; + } + } /* If we added a weaklist, we clear it. Do this *before* calling - the finalizer (__del__), clearing slots, or clearing the instance - dict. */ - + tp_del, clearing slots, or clearing the instance dict. */ if (type->tp_weaklistoffset && !base->tp_weaklistoffset) PyObject_ClearWeakRefs(self); - /* Maybe call finalizer; exit early if resurrected */ if (type->tp_del) { - _PyObject_GC_TRACK(self); type->tp_del(self); - if (self->ob_refcnt > 0) - goto endlabel; /* resurrected */ - else - _PyObject_GC_UNTRACK(self); + if (self->ob_refcnt > 0) { + /* Resurrected */ + goto endlabel; + } + } + if (has_finalizer) { + _PyObject_GC_UNTRACK(self); /* New weakrefs could be created during the finalizer call. - If this occurs, clear them out without calling their - finalizers since they might rely on part of the object - being finalized that has already been destroyed. */ + If this occurs, clear them out without calling their + finalizers since they might rely on part of the object + being finalized that has already been destroyed. */ if (type->tp_weaklistoffset && !base->tp_weaklistoffset) { /* Modeled after GET_WEAKREFS_LISTPTR() */ PyWeakReference **list = (PyWeakReference **) \ @@ -2231,7 +2247,7 @@ /* Initialize tp_flags */ type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | - Py_TPFLAGS_BASETYPE; + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE; if (base->tp_flags & Py_TPFLAGS_HAVE_GC) type->tp_flags |= Py_TPFLAGS_HAVE_GC; @@ -4111,6 +4127,10 @@ COPYSLOT(tp_init); COPYSLOT(tp_alloc); COPYSLOT(tp_is_gc); + if ((type->tp_flags & Py_TPFLAGS_HAVE_FINALIZE) && + (base->tp_flags & Py_TPFLAGS_HAVE_FINALIZE)) { + COPYSLOT(tp_finalize); + } if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) == (base->tp_flags & Py_TPFLAGS_HAVE_GC)) { /* They agree about gc. */ @@ -4737,6 +4757,18 @@ } static PyObject * +wrap_del(PyObject *self, PyObject *args, void *wrapped) +{ + destructor func = (destructor)wrapped; + + if (!check_num_args(args, 0)) + return NULL; + + (*func)(self); + Py_RETURN_NONE; +} + +static PyObject * wrap_richcmpfunc(PyObject *self, PyObject *args, void *wrapped, int op) { richcmpfunc func = (richcmpfunc)wrapped; @@ -5617,16 +5649,12 @@ } static void -slot_tp_del(PyObject *self) +slot_tp_finalize(PyObject *self) { _Py_IDENTIFIER(__del__); PyObject *del, *res; PyObject *error_type, *error_value, *error_traceback; - /* 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); @@ -5643,37 +5671,6 @@ /* 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 */ - - /* __del__ 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 } @@ -5782,7 +5779,7 @@ "see help(type(x)) for signature", PyWrapperFlag_KEYWORDS), TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""), - TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""), + TPSLOT("__del__", tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""), BINSLOT("__add__", nb_add, slot_nb_add, "+"), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 20:01:15 2013 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 30 Jul 2013 20:01:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Set_PEP_442_to_final=2E?= Message-ID: <3c4QYl0dQ6zSxW@mail.python.org> http://hg.python.org/peps/rev/223c8125853a changeset: 5011:223c8125853a user: Antoine Pitrou date: Tue Jul 30 20:01:06 2013 +0200 summary: Set PEP 442 to final. 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 @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Antoine Pitrou BDFL-Delegate: Benjamin Peterson -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 2013-05-18 -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jul 30 20:09:45 2013 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 30 Jul 2013 20:09:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Simplify_examp?= =?utf-8?q?le_of_PyErr=5FFetch=28=29_use?= Message-ID: <3c4QlY2DTCzQct@mail.python.org> http://hg.python.org/cpython/rev/79377c0efa4c changeset: 84912:79377c0efa4c branch: 3.3 parent: 84908:9bf89c909bd4 user: Antoine Pitrou date: Tue Jul 30 20:09:03 2013 +0200 summary: Simplify example of PyErr_Fetch() use files: Doc/extending/newtypes.rst | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -962,10 +962,9 @@ if (self->my_callback != NULL) { PyObject *err_type, *err_value, *err_traceback; - int have_error = PyErr_Occurred() ? 1 : 0; - if (have_error) - PyErr_Fetch(&err_type, &err_value, &err_traceback); + /* This saves the current exception state */ + PyErr_Fetch(&err_type, &err_value, &err_traceback); cbresult = PyObject_CallObject(self->my_callback, NULL); if (cbresult == NULL) @@ -973,8 +972,8 @@ else Py_DECREF(cbresult); - if (have_error) - PyErr_Restore(err_type, err_value, err_traceback); + /* This restores the saved exception state */ + PyErr_Restore(err_type, err_value, err_traceback); Py_DECREF(self->my_callback); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 20:09:46 2013 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 30 Jul 2013 20:09:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_doc_fix?= Message-ID: <3c4QlZ4CbQzQct@mail.python.org> http://hg.python.org/cpython/rev/4e9c8807d029 changeset: 84913:4e9c8807d029 parent: 84911:3f994367a979 parent: 84912:79377c0efa4c user: Antoine Pitrou date: Tue Jul 30 20:09:36 2013 +0200 summary: Merge doc fix files: Doc/extending/newtypes.rst | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -964,10 +964,9 @@ if (self->my_callback != NULL) { PyObject *err_type, *err_value, *err_traceback; - int have_error = PyErr_Occurred() ? 1 : 0; - if (have_error) - PyErr_Fetch(&err_type, &err_value, &err_traceback); + /* This saves the current exception state */ + PyErr_Fetch(&err_type, &err_value, &err_traceback); cbresult = PyObject_CallObject(self->my_callback, NULL); if (cbresult == NULL) @@ -975,8 +974,8 @@ else Py_DECREF(cbresult); - if (have_error) - PyErr_Restore(err_type, err_value, err_traceback); + /* This restores the saved exception state */ + PyErr_Restore(err_type, err_value, err_traceback); Py_DECREF(self->my_callback); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 20:43:27 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 30 Jul 2013 20:43:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4NTg0OiBzL3Rl?= =?utf-8?q?stcleanup/testsetup/_until_we_switch_to_Sphinx_1=2E1=2E?= Message-ID: <3c4RVR0V2Tz7Ljl@mail.python.org> http://hg.python.org/cpython/rev/7b86be4e822c changeset: 84914:7b86be4e822c branch: 3.3 parent: 84912:79377c0efa4c user: R David Murray date: Tue Jul 30 14:42:40 2013 -0400 summary: #18584: s/testcleanup/testsetup/ until we switch to Sphinx 1.1. testcleanup directive is new as of 1.1, and we are currently running 1.0.7. But using testsetup works just as well, and avoids the unknown directive error when building the docs. files: Doc/library/email.iterators.rst | 2 +- Doc/library/email.policy.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/email.iterators.rst b/Doc/library/email.iterators.rst --- a/Doc/library/email.iterators.rst +++ b/Doc/library/email.iterators.rst @@ -68,7 +68,7 @@ text/plain text/plain - .. testcleanup:: + .. testsetup:: >>> somefile.close() diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -85,7 +85,7 @@ >>> p.stdin.close() >>> rc = p.wait() -.. testcleanup:: +.. testsetup:: >>> mymsg.close() >>> mocker.stop() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 20:43:28 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 30 Jul 2013 20:43:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2318584=3A_s/testcleanup/testsetup/_until_we_swit?= =?utf-8?q?ch_to_Sphinx_1=2E1=2E?= Message-ID: <3c4RVS2Jq3zQBY@mail.python.org> http://hg.python.org/cpython/rev/1901a04a3b4a changeset: 84915:1901a04a3b4a parent: 84913:4e9c8807d029 parent: 84914:7b86be4e822c user: R David Murray date: Tue Jul 30 14:43:10 2013 -0400 summary: Merge #18584: s/testcleanup/testsetup/ until we switch to Sphinx 1.1. files: Doc/library/email.iterators.rst | 2 +- Doc/library/email.policy.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/email.iterators.rst b/Doc/library/email.iterators.rst --- a/Doc/library/email.iterators.rst +++ b/Doc/library/email.iterators.rst @@ -68,7 +68,7 @@ text/plain text/plain - .. testcleanup:: + .. testsetup:: >>> somefile.close() diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -85,7 +85,7 @@ >>> p.stdin.close() >>> rc = p.wait() -.. testcleanup:: +.. testsetup:: >>> mymsg.close() >>> mocker.stop() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 21:25:05 2013 From: python-checkins at python.org (ethan.furman) Date: Tue, 30 Jul 2013 21:25:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_fixed_examples_to_work_wit?= =?utf-8?q?h_changed_attribute_names?= Message-ID: <3c4SQT28dkzPCc@mail.python.org> http://hg.python.org/cpython/rev/2b3b873e2b19 changeset: 84916:2b3b873e2b19 user: Ethan Furman date: Tue Jul 30 12:24:25 2013 -0700 summary: fixed examples to work with changed attribute names files: Doc/library/enum.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -483,7 +483,7 @@ ... def __new__(cls): ... value = len(cls.__members__) + 1 ... obj = object.__new__(cls) - ... obj._value = value + ... obj._value_ = value ... return obj ... >>> class Color(AutoNumber): @@ -505,19 +505,19 @@ >>> class OrderedEnum(Enum): ... def __ge__(self, other): ... if self.__class__ is other.__class__: - ... return self._value >= other._value + ... return self.value >= other.value ... return NotImplemented ... def __gt__(self, other): ... if self.__class__ is other.__class__: - ... return self._value > other._value + ... return self.value > other.value ... return NotImplemented ... def __le__(self, other): ... if self.__class__ is other.__class__: - ... return self._value <= other._value + ... return self.value <= other.value ... return NotImplemented ... def __lt__(self, other): ... if self.__class__ is other.__class__: - ... return self._value < other._value + ... return self.value < other.value ... return NotImplemented ... >>> class Grade(OrderedEnum): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 21:38:02 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 30 Jul 2013 21:38:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE4NjAxOiBmaXgg?= =?utf-8?q?error_made_when_difflib_example_was_converted_to_use_=27with=27?= =?utf-8?q?=2E?= Message-ID: <3c4SjQ5SqCzR8P@mail.python.org> http://hg.python.org/cpython/rev/0e1f0faacb0d changeset: 84917:0e1f0faacb0d branch: 3.3 parent: 84914:7b86be4e822c user: R David Murray date: Tue Jul 30 15:37:11 2013 -0400 summary: #18601: fix error made when difflib example was converted to use 'with'. files: Doc/library/difflib.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -752,7 +752,7 @@ # we're passing these as arguments to the diff function fromdate = time.ctime(os.stat(fromfile).st_mtime) todate = time.ctime(os.stat(tofile).st_mtime) - with open(fromlines) as fromf, open(tofile) as tof: + with open(fromfile) as fromf, open(tofile) as tof: fromlines, tolines = list(fromf), list(tof) if options.u: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 21:38:04 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 30 Jul 2013 21:38:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_=2318601=3A_fix_error_made_when_difflib_example?= =?utf-8?q?_was_converted_to_use_=27with=27=2E?= Message-ID: <3c4SjS24Hwz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/c4f377d710da changeset: 84918:c4f377d710da parent: 84916:2b3b873e2b19 parent: 84917:0e1f0faacb0d user: R David Murray date: Tue Jul 30 15:37:43 2013 -0400 summary: Merge: #18601: fix error made when difflib example was converted to use 'with'. files: Doc/library/difflib.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -752,7 +752,7 @@ # we're passing these as arguments to the diff function fromdate = time.ctime(os.stat(fromfile).st_mtime) todate = time.ctime(os.stat(tofile).st_mtime) - with open(fromlines) as fromf, open(tofile) as tof: + with open(fromfile) as fromf, open(tofile) as tof: fromlines, tolines = list(fromf), list(tof) if options.u: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 21:53:45 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 30 Jul 2013 21:53:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE2MjczOiBGaXgg?= =?utf-8?q?tutorial_discussion_of_seek/tell_=28opaque_text-mode_values=29?= =?utf-8?q?=2E?= Message-ID: <3c4T3Y6Zcfz7LjN@mail.python.org> http://hg.python.org/cpython/rev/81bc2d64c006 changeset: 84919:81bc2d64c006 branch: 3.3 parent: 84917:0e1f0faacb0d user: R David Murray date: Tue Jul 30 15:51:57 2013 -0400 summary: #16273: Fix tutorial discussion of seek/tell (opaque text-mode values). Patch by Sijin Joseph. files: Doc/tutorial/inputoutput.rst | 13 +++++++++---- 1 files changed, 9 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 @@ -322,9 +322,11 @@ >>> f.write(s) 18 -``f.tell()`` returns an integer giving the file object's current position in the -file, measured in bytes from the beginning of the file. To change the file -object's position, use ``f.seek(offset, from_what)``. The position is computed +``f.tell()`` returns an integer giving the file object's current position in the file +represented as number of bytes from the beginning of the file when in `binary mode` and +an opaque number when in `text mode`. + +To change the file object's position, use ``f.seek(offset, from_what)``. The position is computed from adding *offset* to a reference point; the reference point is selected by the *from_what* argument. A *from_what* value of 0 measures from the beginning of the file, 1 uses the current file position, and 2 uses the end of the file as @@ -345,7 +347,10 @@ In text files (those opened without a ``b`` in the mode string), only seeks relative to the beginning of the file are allowed (the exception being seeking -to the very file end with ``seek(0, 2)``). +to the very file end with ``seek(0, 2)``) and the only valid *offset* values are +those returned from the ``f.tell()``, or zero. Any other *offset* value produces +undefined behaviour. + When you're done with a file, call ``f.close()`` to close it and free up any system resources taken up by the open file. After calling ``f.close()``, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 21:53:47 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 30 Jul 2013 21:53:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_=2316273=3A_Fix_tutorial_discussion_of_seek/tel?= =?utf-8?q?l_=28opaque_text-mode_values=29=2E?= Message-ID: <3c4T3b37r6z7Ljv@mail.python.org> http://hg.python.org/cpython/rev/c7d9a2159c6c changeset: 84920:c7d9a2159c6c parent: 84918:c4f377d710da parent: 84919:81bc2d64c006 user: R David Murray date: Tue Jul 30 15:53:30 2013 -0400 summary: Merge: #16273: Fix tutorial discussion of seek/tell (opaque text-mode values). files: Doc/tutorial/inputoutput.rst | 13 +++++++++---- 1 files changed, 9 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 @@ -322,9 +322,11 @@ >>> f.write(s) 18 -``f.tell()`` returns an integer giving the file object's current position in the -file, measured in bytes from the beginning of the file. To change the file -object's position, use ``f.seek(offset, from_what)``. The position is computed +``f.tell()`` returns an integer giving the file object's current position in the file +represented as number of bytes from the beginning of the file when in `binary mode` and +an opaque number when in `text mode`. + +To change the file object's position, use ``f.seek(offset, from_what)``. The position is computed from adding *offset* to a reference point; the reference point is selected by the *from_what* argument. A *from_what* value of 0 measures from the beginning of the file, 1 uses the current file position, and 2 uses the end of the file as @@ -345,7 +347,10 @@ In text files (those opened without a ``b`` in the mode string), only seeks relative to the beginning of the file are allowed (the exception being seeking -to the very file end with ``seek(0, 2)``). +to the very file end with ``seek(0, 2)``) and the only valid *offset* values are +those returned from the ``f.tell()``, or zero. Any other *offset* value produces +undefined behaviour. + When you're done with a file, call ``f.close()`` to close it and free up any system resources taken up by the open file. After calling ``f.close()``, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 23:33:43 2013 From: python-checkins at python.org (ned.deily) Date: Tue, 30 Jul 2013 23:33:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1NDk0?= =?utf-8?q?=3A_Install_new_test/support_directory=2E?= Message-ID: <3c4WGv5JWxz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/e6f2f3eda290 changeset: 84921:e6f2f3eda290 branch: 3.3 parent: 84919:81bc2d64c006 user: Ned Deily date: Tue Jul 30 14:30:15 2013 -0700 summary: Issue #15494: Install new test/support directory. files: Makefile.pre.in | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1012,7 +1012,7 @@ tkinter/test/test_ttk site-packages test \ test/capath test/data \ test/cjkencodings test/decimaltestdata test/xmltestdata \ - test/subprocessdata test/sndhdrdata \ + test/subprocessdata test/sndhdrdata test/support \ test/tracedmodules test/encoded_modules \ test/namespace_pkgs \ test/namespace_pkgs/both_portions \ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 30 23:33:45 2013 From: python-checkins at python.org (ned.deily) Date: Tue, 30 Jul 2013 23:33:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315494=3A_merge_from_3=2E3?= Message-ID: <3c4WGx0BCKz7LjN@mail.python.org> http://hg.python.org/cpython/rev/4df2e094f83e changeset: 84922:4df2e094f83e parent: 84920:c7d9a2159c6c parent: 84921:e6f2f3eda290 user: Ned Deily date: Tue Jul 30 14:32:52 2013 -0700 summary: Issue #15494: merge from 3.3 files: Makefile.pre.in | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1012,7 +1012,7 @@ tkinter/test/test_ttk site-packages test \ test/capath test/data \ test/cjkencodings test/decimaltestdata test/xmltestdata \ - test/subprocessdata test/sndhdrdata \ + test/subprocessdata test/sndhdrdata test/support \ test/tracedmodules test/encoded_modules \ test/namespace_pkgs \ test/namespace_pkgs/both_portions \ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 00:55:30 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 00:55:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318481=3A_Add_C_co?= =?utf-8?q?verage_reporting_with_gcov_and_lcov=2E_A_new_make_target?= Message-ID: <3c4Y5G6k7WzSxW@mail.python.org> http://hg.python.org/cpython/rev/85ec2b5bfcd2 changeset: 84923:85ec2b5bfcd2 user: Christian Heimes date: Wed Jul 31 00:55:18 2013 +0200 summary: Issue #18481: Add C coverage reporting with gcov and lcov. A new make target "coverage-report" creates an instrumented Python build, runs unit tests and creates a HTML. The report can be updated with "make coverage-lcov". files: .hgignore | 5 +++ Makefile.pre.in | 47 ++++++++++++++++++++++++++++++++++++- Misc/NEWS | 4 +++ 3 files changed, 55 insertions(+), 1 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -36,6 +36,7 @@ Modules/config.c Modules/ld_so_aix$ Parser/pgen$ +^lcov-report/ ^core ^python-gdb.py ^python.exe-gdb.py @@ -91,3 +92,7 @@ .coverage coverage/ htmlcov/ +*.gcda +*.gcno +*.gcov +coverage.info diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -211,6 +211,12 @@ PROFILE_TASK= $(srcdir)/Tools/pybench/pybench.py -n 2 --with-gc --with-syscheck #PROFILE_TASK= $(srcdir)/Lib/test/regrtest.py +# report files for gcov / lcov coverage report +COVERAGE_INFO= $(abs_builddir)/coverage.info +COVERAGE_REPORT=$(abs_builddir)/lcov-report +COVERAGE_REPORT_OPTIONS=--no-branch-coverage --title "CPython lcov report" + + # === Definitions added by makesetup === @@ -463,11 +469,48 @@ build_all_use_profile: $(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use -fprofile-correction" +# Compile and run with gcov +.PHONY=coverage coverage-lcov coverage-report coverage: @echo "Building with support for coverage checking:" - $(MAKE) clean + $(MAKE) clean profile-removal $(MAKE) all CFLAGS="$(CFLAGS) -O0 -pg -fprofile-arcs -ftest-coverage" LIBS="$(LIBS) -lgcov" +coverage-lcov: + @echo "Creating Coverage HTML report with LCOV:" + @rm -f $(COVERAGE_INFO) + @rm -rf $(COVERAGE_REPORT) + @lcov --capture --directory $(abs_builddir) \ + --base-directory $(realpath $(abs_builddir)) \ + --path $(realpath $(abs_srcdir)) \ + --output-file $(COVERAGE_INFO) + : # remove 3rd party modules and system headers + @lcov --remove $(COVERAGE_INFO) \ + '*/Modules/_ctypes/libffi*/*' \ + '*/Modules/_sha3/keccak/*' \ + '*/Modules/_decimal/libmpdec/*' \ + '*/Modules/expat/*' \ + '*/Modules/zlib/*' \ + '*/Include/*' \ + '/usr/include/*' \ + '/usr/local/include/*' \ + --output-file $(COVERAGE_INFO) + @genhtml $(COVERAGE_INFO) --output-directory $(COVERAGE_REPORT) \ + $(COVERAGE_REPORT_OPTIONS) + @echo + @echo "lcov report at $(COVERAGE_REPORT)/index.html" + @echo + +coverage-report: + : # force rebuilding of parser and importlib + @touch $(GRAMMAR_INPUT) + @touch $(srcdir)/Lib/importlib/_bootstrap.py + : # build with coverage info + $(MAKE) coverage + : # run tests, ignore failures + $(TESTRUNNER) $(TESTOPTS) || true + : # build lcov report + $(MAKE) coverage-lcov # Build the interpreter $(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) @@ -1396,6 +1439,8 @@ profile-removal: find . -name '*.gc??' -exec rm -f {} ';' + rm -f $(COVERAGE_INFO) + rm -rf $(COVERAGE_REPORT) clobber: clean profile-removal -rm -f $(BUILDPYTHON) $(PGEN) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -725,6 +725,10 @@ Build ----- +- Issue #18481: Add C coverage reporting with gcov and lcov. A new make target + "coverage-report" creates an instrumented Python build, runs unit tests + and creates a HTML. The report can be updated with "make coverage-lcov". + - Issue #17845: Clarified the message printed when some module are not built. - Issue #18256: Compilation fix for recent AIX releases. Patch by -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 01:17:14 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 01:17:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Issue_=2318481=3A_documen?= =?utf-8?q?t_new_C_coverage_make_targets?= Message-ID: <3c4YZL4PSMz7LjS@mail.python.org> http://hg.python.org/devguide/rev/116b05b98bea changeset: 633:116b05b98bea user: Christian Heimes date: Wed Jul 31 01:17:03 2013 +0200 summary: Issue #18481: document new C coverage make targets files: coverage.rst | 31 +++++++++++++++++++++++++++++++ experts.rst | 2 +- 2 files changed, 32 insertions(+), 1 deletions(-) diff --git a/coverage.rst b/coverage.rst --- a/coverage.rst +++ b/coverage.rst @@ -227,3 +227,34 @@ worked on (i.e., the in-development version). .. _issue tracker: http://bugs.python.org + + +Measuring coverage of C code with gcov and lcov +""""""""""""""""""""""""""""""""""""""""""""""" + +It's also possible to measure the function, line and branch coverage of +Python's C code. Right now only GCC with `gcov`_ is supported. In order to +create an instrumented build of Python with gcov, run:: + + make coverage + +Then run some code and gather coverage data with the ``gcov`` command. In +order to create a HTML report you can install `lcov`_. The command:: + + make coverage-lcov + +assembles coverage data, removes 3rd party and system libaries and finally +creates a report. You can skip both steps and just run:: + + make coverage-report + +if you like to generate a coverage report for Python's stdlib tests. It takes +about 20 to 30 minutes on a modern computer. + +.. note:: + + Multiple test jobs may not work properly. C coverage reporting has only + been tested with a single test process. + +.. _gcov: http://gcc.gnu.org/onlinedocs/gcc/Gcov.html +.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -324,7 +324,7 @@ georg.brandl str.format eric.smith testing michael.foord, pitrou, ezio.melotti -test coverage ncoghlan, giampaolo.rodola +test coverage ncoghlan, giampaolo.rodola, christian.heimes threads pitrou time and dates lemburg, belopolsky unicode lemburg, ezio.melotti, haypo, benjamin.peterson, pitrou -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jul 31 01:34:00 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 01:34:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_use_of_uninitialized_s?= =?utf-8?q?calar_variable=2C_see_3f994367a979?= Message-ID: <3c4Yxh55f2z7LjS@mail.python.org> http://hg.python.org/cpython/rev/fca77bc5bdb8 changeset: 84924:fca77bc5bdb8 user: Christian Heimes date: Wed Jul 31 01:33:50 2013 +0200 summary: Fix use of uninitialized scalar variable, see 3f994367a979 CID 1058763 files: Modules/_io/iobase.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -210,8 +210,10 @@ /* If `closed` doesn't exist or can't be evaluated as bool, then the object is probably in an unusable state, so ignore. */ res = PyObject_GetAttr(self, _PyIO_str_closed); - if (res == NULL) + if (res == NULL) { PyErr_Clear(); + closed = -1; + } else { closed = PyObject_IsTrue(res); Py_DECREF(res); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 02:36:50 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 02:36:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Test_Py=5FIncRef=28=29_and?= =?utf-8?q?_Py=5FDecRef=28=29_C_functions?= Message-ID: <3c4bLB2rcYzQPD@mail.python.org> http://hg.python.org/cpython/rev/5cea8bc7bc7f changeset: 84925:5cea8bc7bc7f user: Christian Heimes date: Wed Jul 31 02:36:43 2013 +0200 summary: Test Py_IncRef() and Py_DecRef() C functions files: Modules/_testcapimodule.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2614,6 +2614,16 @@ } static PyObject * +test_incref_decref_API(PyObject *ob) +{ + PyObject *obj = PyLong_FromLong(0); + Py_IncRef(ob); + Py_DecRef(obj); + Py_DecRef(obj); + Py_RETURN_NONE; +} + +static PyObject * test_pymem_alloc0(PyObject *self) { void *ptr; @@ -2781,6 +2791,7 @@ {"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_incref_decref_API", (PyCFunction)test_incref_decref_API, 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 Wed Jul 31 04:31:48 2013 From: python-checkins at python.org (terry.reedy) Date: Wed, 31 Jul 2013 04:31:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4NTcz?= =?utf-8?q?=3A_More_copy-paste_fixes_to_assertWarns_entry=2E?= Message-ID: <3c4dtr3BY0zSyG@mail.python.org> http://hg.python.org/cpython/rev/366beee880aa changeset: 84926:366beee880aa branch: 3.3 parent: 84921:e6f2f3eda290 user: Terry Jan Reedy date: Tue Jul 30 22:31:06 2013 -0400 summary: Issue #18573: More copy-paste fixes to assertWarns entry. files: Doc/library/unittest.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -897,12 +897,12 @@ Test that a warning is triggered when *callable* is called with any positional or keyword arguments that are also passed to :meth:`assertWarns`. The test passes if *warning* is triggered and - fails if it isn't. Also, any unexpected exception is an error. + fails if it isn't. Any exception is an error. To catch any of a group of warnings, a tuple containing the warning classes may be passed as *warnings*. If only the *warning* and possibly the *msg* arguments are given, - returns a context manager so that the code under test can be written + return a context manager so that the code under test can be written inline rather than as a function:: with self.assertWarns(SomeWarning): @@ -915,7 +915,7 @@ :attr:`warning` attribute, and the source line which triggered the warnings in the :attr:`filename` and :attr:`lineno` attributes. This can be useful if the intention is to perform additional checks - on the exception raised:: + on the warning caught:: with self.assertWarns(SomeWarning) as cm: do_something() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 04:31:49 2013 From: python-checkins at python.org (terry.reedy) Date: Wed, 31 Jul 2013 04:31:49 +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: <3c4dts56Swz7LjT@mail.python.org> http://hg.python.org/cpython/rev/acfb863b0937 changeset: 84927:acfb863b0937 parent: 84925:5cea8bc7bc7f parent: 84926:366beee880aa user: Terry Jan Reedy date: Tue Jul 30 22:31:30 2013 -0400 summary: Merge with 3.3 files: Doc/library/unittest.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -974,12 +974,12 @@ Test that a warning is triggered when *callable* is called with any positional or keyword arguments that are also passed to :meth:`assertWarns`. The test passes if *warning* is triggered and - fails if it isn't. Also, any unexpected exception is an error. + fails if it isn't. Any exception is an error. To catch any of a group of warnings, a tuple containing the warning classes may be passed as *warnings*. If only the *warning* and possibly the *msg* arguments are given, - returns a context manager so that the code under test can be written + return a context manager so that the code under test can be written inline rather than as a function:: with self.assertWarns(SomeWarning): @@ -992,7 +992,7 @@ :attr:`warning` attribute, and the source line which triggered the warnings in the :attr:`filename` and :attr:`lineno` attributes. This can be useful if the intention is to perform additional checks - on the exception raised:: + on the warning caught:: with self.assertWarns(SomeWarning) as cm: do_something() -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Jul 31 05:50:09 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 31 Jul 2013 05:50:09 +0200 Subject: [Python-checkins] Daily reference leaks (5cea8bc7bc7f): sum=0 Message-ID: results for 5cea8bc7bc7f on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogYhrY2_', '-x'] From python-checkins at python.org Wed Jul 31 09:15:08 2013 From: python-checkins at python.org (ned.deily) Date: Wed, 31 Jul 2013 09:15:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MDcx?= =?utf-8?q?=3A_Extension_module_builds_on_OS_X_could_fail_with_TypeError?= Message-ID: <3c4m9m4j40z7LkM@mail.python.org> http://hg.python.org/cpython/rev/addd9210816b changeset: 84928:addd9210816b branch: 2.7 parent: 84902:6e1dd1ce95b8 user: Ned Deily date: Wed Jul 31 00:14:20 2013 -0700 summary: Issue #18071: Extension module builds on OS X could fail with TypeError if Xcode command line tools were not installed. files: Lib/_osx_support.py | 4 ++-- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py --- a/Lib/_osx_support.py +++ b/Lib/_osx_support.py @@ -53,7 +53,7 @@ def _read_output(commandstring): - """Output from succesful command execution or None""" + """Output from successful command execution or None""" # Similar to os.popen(commandstring, "r").read(), # but without actually using os.popen because that # function is not usable during python bootstrap. @@ -68,7 +68,7 @@ with contextlib.closing(fp) as fp: cmd = "%s 2>/dev/null >'%s'" % (commandstring, fp.name) - return fp.read().decode('utf-8').strip() if not os.system(cmd) else None + return fp.read().strip() if not os.system(cmd) else None def _find_build_tool(toolname): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -74,6 +74,9 @@ 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. +- Issue #18071: C extension module builds on OS X could fail with TypeError + if the Xcode command line tools were not installed. + - Issue #18113: Fixed a refcount leak in the curses.panel module's set_userptr() method. Reported by Atsuo Ishimoto. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 11:58:52 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 11:58:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_=5Fsha3_module_to_actu?= =?utf-8?q?ally_release_the_GIL_around_its_update_function=2E?= Message-ID: <3c4qph6XyyzPDD@mail.python.org> http://hg.python.org/cpython/rev/6f2ba9a33bdf changeset: 84929:6f2ba9a33bdf parent: 84925:5cea8bc7bc7f user: Christian Heimes date: Wed Jul 31 11:58:18 2013 +0200 summary: Fix _sha3 module to actually release the GIL around its update function. gcov is great. files: Modules/_sha3/sha3module.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c --- a/Modules/_sha3/sha3module.c +++ b/Modules/_sha3/sha3module.c @@ -322,7 +322,7 @@ GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); /* add new data, the function takes the length in bits not bytes */ -#ifdef WITH_THREADS +#ifdef WITH_THREAD if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { self->lock = PyThread_allocate_lock(); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 11:58:54 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 11:58:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3c4qpk1FNbz7LjS@mail.python.org> http://hg.python.org/cpython/rev/e825df34af94 changeset: 84930:e825df34af94 parent: 84929:6f2ba9a33bdf parent: 84927:acfb863b0937 user: Christian Heimes date: Wed Jul 31 11:58:41 2013 +0200 summary: merge files: Doc/library/unittest.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -974,12 +974,12 @@ Test that a warning is triggered when *callable* is called with any positional or keyword arguments that are also passed to :meth:`assertWarns`. The test passes if *warning* is triggered and - fails if it isn't. Also, any unexpected exception is an error. + fails if it isn't. Any exception is an error. To catch any of a group of warnings, a tuple containing the warning classes may be passed as *warnings*. If only the *warning* and possibly the *msg* arguments are given, - returns a context manager so that the code under test can be written + return a context manager so that the code under test can be written inline rather than as a function:: with self.assertWarns(SomeWarning): @@ -992,7 +992,7 @@ :attr:`warning` attribute, and the source line which triggered the warnings in the :attr:`filename` and :attr:`lineno` attributes. This can be useful if the intention is to perform additional checks - on the exception raised:: + on the warning caught:: with self.assertWarns(SomeWarning) as cm: do_something() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 13:32:53 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 13:32:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_yet_another_WITH=5FTHREADS?= =?utf-8?q?_typo?= Message-ID: <3c4sv96wRJzT01@mail.python.org> http://hg.python.org/cpython/rev/c3d90db88151 changeset: 84931:c3d90db88151 user: Christian Heimes date: Wed Jul 31 13:32:40 2013 +0200 summary: yet another WITH_THREADS typo files: Modules/_sha3/sha3module.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c --- a/Modules/_sha3/sha3module.c +++ b/Modules/_sha3/sha3module.c @@ -464,7 +464,7 @@ } if (data_obj) { -#ifdef WITH_THREADS +#ifdef WITH_THREAD if (buf.len >= HASHLIB_GIL_MINSIZE) { /* invariant: New objects can't be accessed by other code yet, * thus it's safe to release the GIL without locking the object. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 19:50:06 2013 From: python-checkins at python.org (r.david.murray) Date: Wed, 31 Jul 2013 19:50:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2317616=3A_wave=2Eopen_no?= =?utf-8?q?w_supports_the_=27with=27_statement=2E?= Message-ID: <3c52GQ6kkvzSWf@mail.python.org> http://hg.python.org/cpython/rev/8327780d3841 changeset: 84932:8327780d3841 user: R David Murray date: Wed Jul 31 13:46:08 2013 -0400 summary: #17616: wave.open now supports the 'with' statement. Feature and tests by ClClaudiu.Popa, I added the doc changes. files: Doc/library/aifc.rst | 3 ++- Doc/library/wave.rst | 5 +++++ Doc/whatsnew/3.4.rst | 5 ++++- Lib/test/test_wave.py | 29 +++++++++++++++++++---------- Lib/wave.py | 13 +++++++++++++ Misc/NEWS | 2 ++ 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/Doc/library/aifc.rst b/Doc/library/aifc.rst --- a/Doc/library/aifc.rst +++ b/Doc/library/aifc.rst @@ -51,7 +51,8 @@ used for writing, the file object should be seekable, unless you know ahead of time how many samples you are going to write in total and use :meth:`writeframesraw` and :meth:`setnframes`. - Objects returned by :func:`.open` also supports the :keyword:`with` statement. + The :func:`.open` function may be used in a :keyword:`with` statement. When + the :keyword:`with` block completes, the :meth:`~aifc.close` method is called. .. versionchanged:: 3.4 Support for the :keyword:`with` statement was added. diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -39,6 +39,11 @@ :meth:`close` method is called; it is the caller's responsibility to close the file object. + The :func:`.open` function may be used in a :keyword:`with` statement. When + the :keyword:`with` block completes, the :meth:`Wave_read.close() + ` or :meth:`Wave_write.close() + ` method is called. + .. function:: openfp(file, mode) 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 @@ -239,8 +239,11 @@ The :meth:`~wave.getparams` method now returns a namedtuple rather than a plain tuple. (Contributed by Claudiu Popa in :issue:`17487`.) +:meth:`wave.open` now supports the context manager protocol. (Contributed +by Claudiu Popa in :issue:`17616`.) + stat ---- +---- The stat module is now backed by a C implementation in :mod:`_stat`. A C implementation is required as most of the values aren't standardized and diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -1,7 +1,5 @@ -from test.support import TESTFN, run_unittest -import os +from test.support import TESTFN, unlink import wave -import struct import unittest nchannels = 2 @@ -17,10 +15,7 @@ def tearDown(self): if self.f is not None: self.f.close() - try: - os.remove(TESTFN) - except OSError: - pass + unlink(TESTFN) def test_it(self, test_rounding=False): self.f = wave.open(TESTFN, 'wb') @@ -74,9 +69,23 @@ self.assertEqual(params.comptype, self.f.getcomptype()) self.assertEqual(params.compname, self.f.getcompname()) + def test_context_manager(self): + self.f = wave.open(TESTFN, 'wb') + self.f.setnchannels(nchannels) + self.f.setsampwidth(sampwidth) + self.f.setframerate(framerate) + self.f.close() -def test_main(): - run_unittest(TestWave) + with wave.open(TESTFN) as f: + self.assertFalse(f.getfp().closed) + self.assertIs(f.getfp(), None) + + with open(TESTFN, 'wb') as testfile: + with self.assertRaises(wave.Error): + with wave.open(testfile, 'wb'): + pass + self.assertEqual(testfile.closed, False) + if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Lib/wave.py b/Lib/wave.py --- a/Lib/wave.py +++ b/Lib/wave.py @@ -167,6 +167,13 @@ def __del__(self): self.close() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + # # User visible methods. # @@ -323,6 +330,12 @@ def __del__(self): self.close() + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + # # User visible methods. # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -173,6 +173,8 @@ Library ------- +- Issue #17616: wave.open now supports the context manager protocol. + - Issue #18599: Fix name attribute of _sha1.sha1() object. It now returns 'SHA1' instead of 'SHA'. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 21:54:26 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 31 Jul 2013 21:54:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_style?= Message-ID: <3c551t5DsDzQtN@mail.python.org> http://hg.python.org/cpython/rev/31664b304281 changeset: 84933:31664b304281 parent: 84913:4e9c8807d029 user: Antoine Pitrou date: Tue Jul 30 21:01:23 2013 +0200 summary: Fix style 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 @@ -1382,8 +1382,8 @@ return 0; } -int -static set_main_loader(PyObject *d, const char *filename, const char *loader_name) +static int +set_main_loader(PyObject *d, const char *filename, const char *loader_name) { PyInterpreterState *interp; PyThreadState *tstate; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 21:54:28 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 31 Jul 2013 21:54:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315699=3A_The_read?= =?utf-8?q?line_module_now_uses_PEP_3121-style_module?= Message-ID: <3c551w1BCJzS5Q@mail.python.org> http://hg.python.org/cpython/rev/e4594c7dfeeb changeset: 84934:e4594c7dfeeb user: Antoine Pitrou date: Wed Jul 31 21:52:53 2013 +0200 summary: Issue #15699: The readline module now uses PEP 3121-style module initialization, so as to reclaim allocated resources (Python callbacks) at shutdown. Original patch by Robin Schreiber. files: Misc/NEWS | 4 + Modules/readline.c | 152 +++++++++++++++++++++++--------- 2 files changed, 114 insertions(+), 42 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -173,6 +173,10 @@ Library ------- +- Issue #15699: The readline module now uses PEP 3121-style module + initialization, so as to reclaim allocated resources (Python callbacks) + at shutdown. Original patch by Robin Schreiber. + - Issue #18599: Fix name attribute of _sha1.sha1() object. It now returns 'SHA1' instead of 'SHA'. diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -6,6 +6,7 @@ /* Standard definitions */ #include "Python.h" +#include #include #include #include @@ -74,6 +75,55 @@ (see issue #17289 for the motivation). */ static char *completer_word_break_characters; +typedef struct { + PyObject *completion_display_matches_hook; + PyObject *startup_hook; + PyObject *pre_input_hook; + PyObject *completer; + PyObject *begidx; + PyObject *endidx; +} readlinestate; + + +#define readline_state(o) ((readlinestate *)PyModule_GetState(o)) + +static int +readline_clear(PyObject *m) +{ + readlinestate *state = readline_state(m); + Py_CLEAR(state->completion_display_matches_hook); + Py_CLEAR(state->startup_hook); + Py_CLEAR(state->pre_input_hook); + Py_CLEAR(state->completer); + Py_CLEAR(state->begidx); + Py_CLEAR(state->endidx); + return 0; +} + +static int +readline_traverse(PyObject *m, visitproc visit, void *arg) +{ + readlinestate *state = readline_state(m); + Py_VISIT(state->completion_display_matches_hook); + Py_VISIT(state->startup_hook); + Py_VISIT(state->pre_input_hook); + Py_VISIT(state->completer); + Py_VISIT(state->begidx); + Py_VISIT(state->endidx); + return 0; +} + +static void +readline_free(void *m) +{ + readline_clear((PyObject *)m); +} + +static PyModuleDef readlinemodule; + +#define readlinestate_global ((readlinestate *)PyModule_GetState(PyState_FindModule(&readlinemodule))) + + /* Exported function to send one line to readline's init file parser */ static PyObject * @@ -250,23 +300,21 @@ /* Exported functions to specify hook functions in Python */ -static PyObject *completion_display_matches_hook = NULL; -static PyObject *startup_hook = NULL; #ifdef HAVE_RL_PRE_INPUT_HOOK -static PyObject *pre_input_hook = NULL; + #endif static PyObject * set_completion_display_matches_hook(PyObject *self, PyObject *args) { PyObject *result = set_hook("completion_display_matches_hook", - &completion_display_matches_hook, args); + &readlinestate_global->completion_display_matches_hook, args); #ifdef HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK /* We cannot set this hook globally, since it replaces the default completion display. */ rl_completion_display_matches_hook = - completion_display_matches_hook ? + readlinestate_global->completion_display_matches_hook ? #if defined(_RL_FUNCTION_TYPEDEF) (rl_compdisp_func_t *)on_completion_display_matches_hook : 0; #else @@ -287,7 +335,7 @@ static PyObject * set_startup_hook(PyObject *self, PyObject *args) { - return set_hook("startup_hook", &startup_hook, args); + return set_hook("startup_hook", &readlinestate_global->startup_hook, args); } PyDoc_STRVAR(doc_set_startup_hook, @@ -304,7 +352,7 @@ static PyObject * set_pre_input_hook(PyObject *self, PyObject *args) { - return set_hook("pre_input_hook", &pre_input_hook, args); + return set_hook("pre_input_hook", &readlinestate_global->pre_input_hook, args); } PyDoc_STRVAR(doc_set_pre_input_hook, @@ -319,10 +367,10 @@ /* Exported function to specify a word completer in Python */ -static PyObject *completer = NULL; -static PyObject *begidx = NULL; -static PyObject *endidx = NULL; + + + /* Get the completion type for the scope of the tab-completion */ @@ -342,8 +390,8 @@ static PyObject * get_begidx(PyObject *self, PyObject *noarg) { - Py_INCREF(begidx); - return begidx; + Py_INCREF(readlinestate_global->begidx); + return readlinestate_global->begidx; } PyDoc_STRVAR(doc_get_begidx, @@ -356,8 +404,8 @@ static PyObject * get_endidx(PyObject *self, PyObject *noarg) { - Py_INCREF(endidx); - return endidx; + Py_INCREF(readlinestate_global->endidx); + return readlinestate_global->endidx; } PyDoc_STRVAR(doc_get_endidx, @@ -522,7 +570,7 @@ static PyObject * set_completer(PyObject *self, PyObject *args) { - return set_hook("completer", &completer, args); + return set_hook("completer", &readlinestate_global->completer, args); } PyDoc_STRVAR(doc_set_completer, @@ -536,11 +584,11 @@ static PyObject * get_completer(PyObject *self, PyObject *noargs) { - if (completer == NULL) { + if (readlinestate_global->completer == NULL) { Py_RETURN_NONE; } - Py_INCREF(completer); - return completer; + Py_INCREF(readlinestate_global->completer); + return readlinestate_global->completer; } PyDoc_STRVAR(doc_get_completer, @@ -744,9 +792,6 @@ int result = 0; if (func != NULL) { PyObject *r; -#ifdef WITH_THREAD - PyGILState_STATE gilstate = PyGILState_Ensure(); -#endif r = PyObject_CallFunction(func, NULL); if (r == NULL) goto error; @@ -763,9 +808,6 @@ PyErr_Clear(); Py_XDECREF(r); done: -#ifdef WITH_THREAD - PyGILState_Release(gilstate); -#endif return result; } return result; @@ -774,14 +816,30 @@ static int on_startup_hook(void) { - return on_hook(startup_hook); + int r; +#ifdef WITH_THREAD + PyGILState_STATE gilstate = PyGILState_Ensure(); +#endif + r = on_hook(readlinestate_global->startup_hook); +#ifdef WITH_THREAD + PyGILState_Release(gilstate); +#endif + return r; } #ifdef HAVE_RL_PRE_INPUT_HOOK static int on_pre_input_hook(void) { - return on_hook(pre_input_hook); + int r; +#ifdef WITH_THREAD + PyGILState_STATE gilstate = PyGILState_Ensure(); +#endif + r = on_hook(readlinestate_global->pre_input_hook); +#ifdef WITH_THREAD + PyGILState_Release(gilstate); +#endif + return r; } #endif @@ -808,7 +866,7 @@ if (PyList_SetItem(m, i, s) == -1) goto error; } - r = PyObject_CallFunction(completion_display_matches_hook, + r = PyObject_CallFunction(readlinestate_global->completion_display_matches_hook, "sOi", matches[0], m, max_length); Py_DECREF(m); m=NULL; @@ -838,13 +896,13 @@ on_completion(const char *text, int state) { char *result = NULL; - if (completer != NULL) { + if (readlinestate_global->completer != NULL) { PyObject *r; #ifdef WITH_THREAD PyGILState_STATE gilstate = PyGILState_Ensure(); #endif rl_attempted_completion_over = 1; - r = PyObject_CallFunction(completer, "si", text, state); + r = PyObject_CallFunction(readlinestate_global->completer, "si", text, state); if (r == NULL) goto error; if (r == Py_None) { @@ -877,24 +935,32 @@ static char ** flex_complete(char *text, int start, int end) { + char **result; +#ifdef WITH_THREAD + PyGILState_STATE gilstate = PyGILState_Ensure(); +#endif #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER rl_completion_append_character ='\0'; #endif #ifdef HAVE_RL_COMPLETION_SUPPRESS_APPEND rl_completion_suppress_append = 0; #endif - Py_XDECREF(begidx); - Py_XDECREF(endidx); - begidx = PyLong_FromLong((long) start); - endidx = PyLong_FromLong((long) end); - return completion_matches(text, *on_completion); + Py_XDECREF(readlinestate_global->begidx); + Py_XDECREF(readlinestate_global->endidx); + readlinestate_global->begidx = PyLong_FromLong((long) start); + readlinestate_global->endidx = PyLong_FromLong((long) end); + result = completion_matches(text, *on_completion); +#ifdef WITH_THREAD + PyGILState_Release(gilstate); +#endif + return result; } /* Helper to initialize GNU readline properly. */ static void -setup_readline(void) +setup_readline(readlinestate *mod_state) { #ifdef SAVE_LOCALE char *saved_locale = strdup(setlocale(LC_CTYPE, NULL)); @@ -931,8 +997,8 @@ strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ - begidx = PyLong_FromLong(0L); - endidx = PyLong_FromLong(0L); + mod_state->begidx = PyLong_FromLong(0L); + mod_state->endidx = PyLong_FromLong(0L); /* Initialize (allows .inputrc to override) * * XXX: A bug in the readline-2.2 library causes a memory leak @@ -1154,12 +1220,12 @@ PyModuleDef_HEAD_INIT, "readline", doc_module, - -1, + sizeof(readlinestate), readline_methods, NULL, - NULL, - NULL, - NULL + readline_traverse, + readline_clear, + readline_free }; @@ -1167,6 +1233,7 @@ PyInit_readline(void) { PyObject *m; + readlinestate *mod_state; #ifdef __APPLE__ if (strncmp(rl_library_version, libedit_version_tag, strlen(libedit_version_tag)) == 0) { @@ -1183,7 +1250,8 @@ if (m == NULL) return NULL; + mod_state = (readlinestate *) PyModule_GetState(m); PyOS_ReadlineFunctionPointer = call_readline; - setup_readline(); + setup_readline(mod_state); return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 21:54:29 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 31 Jul 2013 21:54:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge?= Message-ID: <3c551x64nhzSPp@mail.python.org> http://hg.python.org/cpython/rev/3a7dedc7067f changeset: 84935:3a7dedc7067f parent: 84934:e4594c7dfeeb parent: 84932:8327780d3841 user: Antoine Pitrou date: Wed Jul 31 21:54:18 2013 +0200 summary: Merge files: .hgignore | 5 ++ Doc/library/aifc.rst | 3 +- Doc/library/difflib.rst | 2 +- Doc/library/email.iterators.rst | 2 +- Doc/library/email.policy.rst | 2 +- Doc/library/enum.rst | 10 ++-- Doc/library/unittest.rst | 6 +- Doc/library/wave.rst | 5 ++ Doc/tutorial/inputoutput.rst | 13 +++- Doc/whatsnew/3.4.rst | 5 +- Lib/test/test_wave.py | 29 ++++++++---- Lib/wave.py | 13 +++++ Makefile.pre.in | 49 ++++++++++++++++++++- Misc/NEWS | 6 ++ Modules/_io/iobase.c | 4 +- Modules/_sha3/sha3module.c | 4 +- Modules/_testcapimodule.c | 11 ++++ 17 files changed, 137 insertions(+), 32 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -36,6 +36,7 @@ Modules/config.c Modules/ld_so_aix$ Parser/pgen$ +^lcov-report/ ^core ^python-gdb.py ^python.exe-gdb.py @@ -91,3 +92,7 @@ .coverage coverage/ htmlcov/ +*.gcda +*.gcno +*.gcov +coverage.info diff --git a/Doc/library/aifc.rst b/Doc/library/aifc.rst --- a/Doc/library/aifc.rst +++ b/Doc/library/aifc.rst @@ -51,7 +51,8 @@ used for writing, the file object should be seekable, unless you know ahead of time how many samples you are going to write in total and use :meth:`writeframesraw` and :meth:`setnframes`. - Objects returned by :func:`.open` also supports the :keyword:`with` statement. + The :func:`.open` function may be used in a :keyword:`with` statement. When + the :keyword:`with` block completes, the :meth:`~aifc.close` method is called. .. versionchanged:: 3.4 Support for the :keyword:`with` statement was added. diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -752,7 +752,7 @@ # we're passing these as arguments to the diff function fromdate = time.ctime(os.stat(fromfile).st_mtime) todate = time.ctime(os.stat(tofile).st_mtime) - with open(fromlines) as fromf, open(tofile) as tof: + with open(fromfile) as fromf, open(tofile) as tof: fromlines, tolines = list(fromf), list(tof) if options.u: diff --git a/Doc/library/email.iterators.rst b/Doc/library/email.iterators.rst --- a/Doc/library/email.iterators.rst +++ b/Doc/library/email.iterators.rst @@ -68,7 +68,7 @@ text/plain text/plain - .. testcleanup:: + .. testsetup:: >>> somefile.close() diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -85,7 +85,7 @@ >>> p.stdin.close() >>> rc = p.wait() -.. testcleanup:: +.. testsetup:: >>> mymsg.close() >>> mocker.stop() diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -483,7 +483,7 @@ ... def __new__(cls): ... value = len(cls.__members__) + 1 ... obj = object.__new__(cls) - ... obj._value = value + ... obj._value_ = value ... return obj ... >>> class Color(AutoNumber): @@ -505,19 +505,19 @@ >>> class OrderedEnum(Enum): ... def __ge__(self, other): ... if self.__class__ is other.__class__: - ... return self._value >= other._value + ... return self.value >= other.value ... return NotImplemented ... def __gt__(self, other): ... if self.__class__ is other.__class__: - ... return self._value > other._value + ... return self.value > other.value ... return NotImplemented ... def __le__(self, other): ... if self.__class__ is other.__class__: - ... return self._value <= other._value + ... return self.value <= other.value ... return NotImplemented ... def __lt__(self, other): ... if self.__class__ is other.__class__: - ... return self._value < other._value + ... return self.value < other.value ... return NotImplemented ... >>> class Grade(OrderedEnum): diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -974,12 +974,12 @@ Test that a warning is triggered when *callable* is called with any positional or keyword arguments that are also passed to :meth:`assertWarns`. The test passes if *warning* is triggered and - fails if it isn't. Also, any unexpected exception is an error. + fails if it isn't. Any exception is an error. To catch any of a group of warnings, a tuple containing the warning classes may be passed as *warnings*. If only the *warning* and possibly the *msg* arguments are given, - returns a context manager so that the code under test can be written + return a context manager so that the code under test can be written inline rather than as a function:: with self.assertWarns(SomeWarning): @@ -992,7 +992,7 @@ :attr:`warning` attribute, and the source line which triggered the warnings in the :attr:`filename` and :attr:`lineno` attributes. This can be useful if the intention is to perform additional checks - on the exception raised:: + on the warning caught:: with self.assertWarns(SomeWarning) as cm: do_something() diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -39,6 +39,11 @@ :meth:`close` method is called; it is the caller's responsibility to close the file object. + The :func:`.open` function may be used in a :keyword:`with` statement. When + the :keyword:`with` block completes, the :meth:`Wave_read.close() + ` or :meth:`Wave_write.close() + ` method is called. + .. function:: openfp(file, mode) diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -322,9 +322,11 @@ >>> f.write(s) 18 -``f.tell()`` returns an integer giving the file object's current position in the -file, measured in bytes from the beginning of the file. To change the file -object's position, use ``f.seek(offset, from_what)``. The position is computed +``f.tell()`` returns an integer giving the file object's current position in the file +represented as number of bytes from the beginning of the file when in `binary mode` and +an opaque number when in `text mode`. + +To change the file object's position, use ``f.seek(offset, from_what)``. The position is computed from adding *offset* to a reference point; the reference point is selected by the *from_what* argument. A *from_what* value of 0 measures from the beginning of the file, 1 uses the current file position, and 2 uses the end of the file as @@ -345,7 +347,10 @@ In text files (those opened without a ``b`` in the mode string), only seeks relative to the beginning of the file are allowed (the exception being seeking -to the very file end with ``seek(0, 2)``). +to the very file end with ``seek(0, 2)``) and the only valid *offset* values are +those returned from the ``f.tell()``, or zero. Any other *offset* value produces +undefined behaviour. + When you're done with a file, call ``f.close()`` to close it and free up any system resources taken up by the open file. After calling ``f.close()``, 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 @@ -239,8 +239,11 @@ The :meth:`~wave.getparams` method now returns a namedtuple rather than a plain tuple. (Contributed by Claudiu Popa in :issue:`17487`.) +:meth:`wave.open` now supports the context manager protocol. (Contributed +by Claudiu Popa in :issue:`17616`.) + stat ---- +---- The stat module is now backed by a C implementation in :mod:`_stat`. A C implementation is required as most of the values aren't standardized and diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -1,7 +1,5 @@ -from test.support import TESTFN, run_unittest -import os +from test.support import TESTFN, unlink import wave -import struct import unittest nchannels = 2 @@ -17,10 +15,7 @@ def tearDown(self): if self.f is not None: self.f.close() - try: - os.remove(TESTFN) - except OSError: - pass + unlink(TESTFN) def test_it(self, test_rounding=False): self.f = wave.open(TESTFN, 'wb') @@ -74,9 +69,23 @@ self.assertEqual(params.comptype, self.f.getcomptype()) self.assertEqual(params.compname, self.f.getcompname()) + def test_context_manager(self): + self.f = wave.open(TESTFN, 'wb') + self.f.setnchannels(nchannels) + self.f.setsampwidth(sampwidth) + self.f.setframerate(framerate) + self.f.close() -def test_main(): - run_unittest(TestWave) + with wave.open(TESTFN) as f: + self.assertFalse(f.getfp().closed) + self.assertIs(f.getfp(), None) + + with open(TESTFN, 'wb') as testfile: + with self.assertRaises(wave.Error): + with wave.open(testfile, 'wb'): + pass + self.assertEqual(testfile.closed, False) + if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Lib/wave.py b/Lib/wave.py --- a/Lib/wave.py +++ b/Lib/wave.py @@ -167,6 +167,13 @@ def __del__(self): self.close() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + # # User visible methods. # @@ -323,6 +330,12 @@ def __del__(self): self.close() + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + # # User visible methods. # diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -211,6 +211,12 @@ PROFILE_TASK= $(srcdir)/Tools/pybench/pybench.py -n 2 --with-gc --with-syscheck #PROFILE_TASK= $(srcdir)/Lib/test/regrtest.py +# report files for gcov / lcov coverage report +COVERAGE_INFO= $(abs_builddir)/coverage.info +COVERAGE_REPORT=$(abs_builddir)/lcov-report +COVERAGE_REPORT_OPTIONS=--no-branch-coverage --title "CPython lcov report" + + # === Definitions added by makesetup === @@ -463,11 +469,48 @@ build_all_use_profile: $(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use -fprofile-correction" +# Compile and run with gcov +.PHONY=coverage coverage-lcov coverage-report coverage: @echo "Building with support for coverage checking:" - $(MAKE) clean + $(MAKE) clean profile-removal $(MAKE) all CFLAGS="$(CFLAGS) -O0 -pg -fprofile-arcs -ftest-coverage" LIBS="$(LIBS) -lgcov" +coverage-lcov: + @echo "Creating Coverage HTML report with LCOV:" + @rm -f $(COVERAGE_INFO) + @rm -rf $(COVERAGE_REPORT) + @lcov --capture --directory $(abs_builddir) \ + --base-directory $(realpath $(abs_builddir)) \ + --path $(realpath $(abs_srcdir)) \ + --output-file $(COVERAGE_INFO) + : # remove 3rd party modules and system headers + @lcov --remove $(COVERAGE_INFO) \ + '*/Modules/_ctypes/libffi*/*' \ + '*/Modules/_sha3/keccak/*' \ + '*/Modules/_decimal/libmpdec/*' \ + '*/Modules/expat/*' \ + '*/Modules/zlib/*' \ + '*/Include/*' \ + '/usr/include/*' \ + '/usr/local/include/*' \ + --output-file $(COVERAGE_INFO) + @genhtml $(COVERAGE_INFO) --output-directory $(COVERAGE_REPORT) \ + $(COVERAGE_REPORT_OPTIONS) + @echo + @echo "lcov report at $(COVERAGE_REPORT)/index.html" + @echo + +coverage-report: + : # force rebuilding of parser and importlib + @touch $(GRAMMAR_INPUT) + @touch $(srcdir)/Lib/importlib/_bootstrap.py + : # build with coverage info + $(MAKE) coverage + : # run tests, ignore failures + $(TESTRUNNER) $(TESTOPTS) || true + : # build lcov report + $(MAKE) coverage-lcov # Build the interpreter $(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) @@ -1012,7 +1055,7 @@ tkinter/test/test_ttk site-packages test \ test/capath test/data \ test/cjkencodings test/decimaltestdata test/xmltestdata \ - test/subprocessdata test/sndhdrdata \ + test/subprocessdata test/sndhdrdata test/support \ test/tracedmodules test/encoded_modules \ test/namespace_pkgs \ test/namespace_pkgs/both_portions \ @@ -1396,6 +1439,8 @@ profile-removal: find . -name '*.gc??' -exec rm -f {} ';' + rm -f $(COVERAGE_INFO) + rm -rf $(COVERAGE_REPORT) clobber: clean profile-removal -rm -f $(BUILDPYTHON) $(PGEN) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -177,6 +177,8 @@ initialization, so as to reclaim allocated resources (Python callbacks) at shutdown. Original patch by Robin Schreiber. +- Issue #17616: wave.open now supports the context manager protocol. + - Issue #18599: Fix name attribute of _sha1.sha1() object. It now returns 'SHA1' instead of 'SHA'. @@ -729,6 +731,10 @@ Build ----- +- Issue #18481: Add C coverage reporting with gcov and lcov. A new make target + "coverage-report" creates an instrumented Python build, runs unit tests + and creates a HTML. The report can be updated with "make coverage-lcov". + - Issue #17845: Clarified the message printed when some module are not built. - Issue #18256: Compilation fix for recent AIX releases. Patch by diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -210,8 +210,10 @@ /* If `closed` doesn't exist or can't be evaluated as bool, then the object is probably in an unusable state, so ignore. */ res = PyObject_GetAttr(self, _PyIO_str_closed); - if (res == NULL) + if (res == NULL) { PyErr_Clear(); + closed = -1; + } else { closed = PyObject_IsTrue(res); Py_DECREF(res); diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c --- a/Modules/_sha3/sha3module.c +++ b/Modules/_sha3/sha3module.c @@ -322,7 +322,7 @@ GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); /* add new data, the function takes the length in bits not bytes */ -#ifdef WITH_THREADS +#ifdef WITH_THREAD if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { self->lock = PyThread_allocate_lock(); } @@ -464,7 +464,7 @@ } if (data_obj) { -#ifdef WITH_THREADS +#ifdef WITH_THREAD if (buf.len >= HASHLIB_GIL_MINSIZE) { /* invariant: New objects can't be accessed by other code yet, * thus it's safe to release the GIL without locking the object. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2614,6 +2614,16 @@ } static PyObject * +test_incref_decref_API(PyObject *ob) +{ + PyObject *obj = PyLong_FromLong(0); + Py_IncRef(ob); + Py_DecRef(obj); + Py_DecRef(obj); + Py_RETURN_NONE; +} + +static PyObject * test_pymem_alloc0(PyObject *self) { void *ptr; @@ -2781,6 +2791,7 @@ {"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_incref_decref_API", (PyCFunction)test_incref_decref_API, 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 Wed Jul 31 23:15:46 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 31 Jul 2013 23:15:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318214=3A_Improve_?= =?utf-8?q?finalization_of_Python_modules_to_avoid_setting_their?= Message-ID: <3c56qk45gqzPmt@mail.python.org> http://hg.python.org/cpython/rev/79e2f5bbc30c changeset: 84936:79e2f5bbc30c user: Antoine Pitrou date: Wed Jul 31 23:14:08 2013 +0200 summary: Issue #18214: Improve finalization of Python modules to avoid setting their globals to None, in most cases. files: Lib/rlcompleter.py | 6 + Lib/site.py | 39 +++++- Lib/test/final_a.py | 19 +++ Lib/test/final_b.py | 19 +++ Lib/test/test_module.py | 15 ++- Lib/test/test_sys.py | 2 +- Misc/NEWS | 3 + Objects/moduleobject.c | 29 +++- Python/import.c | 155 +++++++++++---------------- 9 files changed, 178 insertions(+), 109 deletions(-) diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -29,6 +29,7 @@ """ +import atexit import builtins import __main__ @@ -158,3 +159,8 @@ pass else: readline.set_completer(Completer().complete) + # Release references early at shutdown (the readline module's + # contents are quasi-immortal, and the completer function holds a + # reference to globals). + atexit.register(lambda: readline.set_completer(None)) + diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -68,6 +68,7 @@ ImportError exception, it is silently ignored. """ +import atexit import sys import os import re @@ -86,6 +87,25 @@ USER_BASE = None +_no_builtin = object() + +def _patch_builtins(**items): + # When patching builtins, we make some objects almost immortal + # (builtins are only reclaimed at the very end of the interpreter + # shutdown sequence). To avoid keeping to many references alive, + # we register callbacks to undo our builtins additions. + old_items = {k: getattr(builtins, k, _no_builtin) for k in items} + def unpatch(old_items=old_items): + for k, v in old_items.items(): + if v is _no_builtin: + delattr(builtins, k) + else: + setattr(builtins, k, v) + for k, v in items.items(): + setattr(builtins, k, v) + atexit.register(unpatch) + + def makepath(*paths): dir = os.path.join(*paths) try: @@ -357,8 +377,7 @@ except: pass raise SystemExit(code) - builtins.quit = Quitter('quit') - builtins.exit = Quitter('exit') + _patch_builtins(quit=Quitter('quit'), exit=Quitter('exit')) class _Printer(object): @@ -423,20 +442,20 @@ def setcopyright(): """Set 'copyright' and 'credits' in builtins""" - builtins.copyright = _Printer("copyright", sys.copyright) + _patch_builtins(copyright=_Printer("copyright", sys.copyright)) if sys.platform[:4] == 'java': - builtins.credits = _Printer( + _patch_builtins(credits=_Printer( "credits", - "Jython is maintained by the Jython developers (www.jython.org).") + "Jython is maintained by the Jython developers (www.jython.org).")) else: - builtins.credits = _Printer("credits", """\ + _patch_builtins(credits=_Printer("credits", """\ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands - for supporting Python development. See www.python.org for more information.""") + for supporting Python development. See www.python.org for more information.""")) here = os.path.dirname(os.__file__) - builtins.license = _Printer( + _patch_builtins(license=_Printer( "license", "See http://www.python.org/%.3s/license.html" % sys.version, ["LICENSE.txt", "LICENSE"], - [os.path.join(here, os.pardir), here, os.curdir]) + [os.path.join(here, os.pardir), here, os.curdir])) class _Helper(object): @@ -453,7 +472,7 @@ return pydoc.help(*args, **kwds) def sethelper(): - builtins.help = _Helper() + _patch_builtins(help=_Helper()) def enablerlcompleter(): """Enable default readline configuration on interactive prompts, by diff --git a/Lib/test/final_a.py b/Lib/test/final_a.py new file mode 100644 --- /dev/null +++ b/Lib/test/final_a.py @@ -0,0 +1,19 @@ +""" +Fodder for module finalization tests in test_module. +""" + +import shutil +import test.final_b + +x = 'a' + +class C: + def __del__(self): + # Inspect module globals and builtins + print("x =", x) + print("final_b.x =", test.final_b.x) + print("shutil.rmtree =", getattr(shutil.rmtree, '__name__', None)) + print("len =", getattr(len, '__name__', None)) + +c = C() +_underscored = C() diff --git a/Lib/test/final_b.py b/Lib/test/final_b.py new file mode 100644 --- /dev/null +++ b/Lib/test/final_b.py @@ -0,0 +1,19 @@ +""" +Fodder for module finalization tests in test_module. +""" + +import shutil +import test.final_a + +x = 'b' + +class C: + def __del__(self): + # Inspect module globals and builtins + print("x =", x) + print("final_a.x =", test.final_a.x) + print("shutil.rmtree =", getattr(shutil.rmtree, '__name__', None)) + print("len =", getattr(len, '__name__', None)) + +c = C() +_underscored = C() 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 @@ -1,6 +1,7 @@ # Test the module type import unittest from test.support import run_unittest, gc_collect +from test.script_helper import assert_python_ok import sys ModuleType = type(sys) @@ -70,7 +71,6 @@ "__loader__": None, "__package__": None}) self.assertTrue(foo.__dict__ is d) - @unittest.expectedFailure def test_dont_clear_dict(self): # See issue 7140. def f(): @@ -181,6 +181,19 @@ self.assertEqual(r[:25], "") + def test_module_finalization_at_shutdown(self): + # Module globals and builtins should still be available during shutdown + rc, out, err = assert_python_ok("-c", "from test import final_a") + self.assertFalse(err) + lines = out.splitlines() + self.assertEqual(set(lines), { + b"x = a", + b"x = b", + b"final_a.x = a", + b"final_b.x = b", + b"len = len", + b"shutil.rmtree = rmtree"}) + # frozen and namespace module reprs are tested in importlib. 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 @@ -810,7 +810,7 @@ # memoryview check(memoryview(b''), size('Pnin 2P2n2i5P 3cPn')) # module - check(unittest, size('PnP')) + check(unittest, size('PnPPP')) # None check(None, size('')) # NotImplementedType diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18214: Improve finalization of Python modules to avoid setting + their globals to None, in most cases. + - Issue #18112: PEP 442 implementation (safe object finalization). - Issue #18552: Check return value of PyArena_AddPyObject() in diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -11,6 +11,8 @@ PyObject *md_dict; struct PyModuleDef *md_def; void *md_state; + PyObject *md_weaklist; + PyObject *md_name; /* for logging purposes after md_dict is cleared */ } PyModuleObject; static PyMemberDef module_members[] = { @@ -27,7 +29,8 @@ static int -module_init_dict(PyObject *md_dict, PyObject *name, PyObject *doc) +module_init_dict(PyModuleObject *mod, PyObject *md_dict, + PyObject *name, PyObject *doc) { if (md_dict == NULL) return -1; @@ -42,6 +45,11 @@ return -1; if (PyDict_SetItemString(md_dict, "__loader__", Py_None) != 0) return -1; + if (PyUnicode_CheckExact(name)) { + Py_INCREF(name); + Py_XDECREF(mod->md_name); + mod->md_name = name; + } return 0; } @@ -56,8 +64,10 @@ return NULL; m->md_def = NULL; m->md_state = NULL; + m->md_weaklist = NULL; + m->md_name = NULL; m->md_dict = PyDict_New(); - if (module_init_dict(m->md_dict, name, NULL) != 0) + if (module_init_dict(m, m->md_dict, name, NULL) != 0) goto fail; PyObject_GC_Track(m); return (PyObject *)m; @@ -362,7 +372,7 @@ return -1; m->md_dict = dict; } - if (module_init_dict(dict, name, doc) < 0) + if (module_init_dict(m, dict, name, doc) < 0) return -1; return 0; } @@ -371,12 +381,15 @@ module_dealloc(PyModuleObject *m) { PyObject_GC_UnTrack(m); + if (Py_VerboseFlag && m->md_name) { + PySys_FormatStderr("# destroy %S\n", m->md_name); + } + if (m->md_weaklist != NULL) + PyObject_ClearWeakRefs((PyObject *) m); if (m->md_def && m->md_def->m_free) m->md_def->m_free(m); - if (m->md_dict != NULL) { - _PyModule_Clear((PyObject *)m); - Py_DECREF(m->md_dict); - } + Py_XDECREF(m->md_dict); + Py_XDECREF(m->md_name); if (m->md_state != NULL) PyMem_FREE(m->md_state); Py_TYPE(m)->tp_free((PyObject *)m); @@ -522,7 +535,7 @@ (traverseproc)module_traverse, /* tp_traverse */ (inquiry)module_clear, /* tp_clear */ 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ + offsetof(PyModuleObject, md_weaklist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ module_methods, /* tp_methods */ diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -277,6 +277,7 @@ "path", "argv", "ps1", "ps2", "last_type", "last_value", "last_traceback", "path_hooks", "path_importer_cache", "meta_path", + "__interactivehook__", /* misc stuff */ "flags", "float_info", NULL @@ -289,40 +290,17 @@ 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 */ void PyImport_Cleanup(void) { - Py_ssize_t pos, ndone; + Py_ssize_t pos; PyObject *key, *value, *dict; PyInterpreterState *interp = PyThreadState_GET()->interp; PyObject *modules = interp->modules; + PyObject *builtins = interp->builtins; + PyObject *weaklist = NULL; if (modules == NULL) return; /* Already done */ @@ -333,6 +311,8 @@ deleted *last* of all, they would come too late in the normal destruction order. Sigh. */ + /* XXX Perhaps these precautions are obsolete. Who knows? */ + value = PyDict_GetItemString(modules, "builtins"); if (value != NULL && PyModule_Check(value)) { dict = PyModule_GetDict(value); @@ -360,87 +340,84 @@ } } - /* First, delete __main__ */ - value = PyDict_GetItemString(modules, "__main__"); - if (value != NULL && PyModule_Check(value)) { - if (Py_VerboseFlag) - PySys_WriteStderr("# cleanup __main__\n"); - _PyModule_Clear(value); - PyDict_SetItemString(modules, "__main__", Py_None); + /* We prepare a list which will receive (name, weakref) tuples of + modules when they are removed from sys.modules. The name is used + for diagnosis messages (in verbose mode), while the weakref helps + detect those modules which have been held alive. */ + weaklist = PyList_New(0); + +#define STORE_MODULE_WEAKREF(mod) \ + if (weaklist != NULL) { \ + PyObject *name = PyModule_GetNameObject(mod); \ + PyObject *wr = PyWeakref_NewRef(mod, NULL); \ + if (name && wr) { \ + PyObject *tup = PyTuple_Pack(2, name, wr); \ + PyList_Append(weaklist, tup); \ + Py_XDECREF(tup); \ + } \ + Py_XDECREF(name); \ + Py_XDECREF(wr); \ + if (PyErr_Occurred()) \ + PyErr_Clear(); \ } - /* The special treatment of "builtins" here is because even - when it's not referenced as a module, its dictionary is - referenced by almost every module's __builtins__. Since - deleting a module clears its dictionary (even if there are - references left to it), we need to delete the "builtins" - module last. Likewise, we don't delete sys until the very - end because it is implicitly referenced (e.g. by print). - - Also note that we 'delete' modules by replacing their entry - in the modules dict with None, rather than really deleting - them; this avoids a rehash of the modules dictionary and - also marks them as "non existent" so they won't be - re-imported. */ - - /* Next, repeatedly delete modules with a reference count of - one (skipping builtins and sys) and delete them */ - do { - ndone = 0; - pos = 0; - while (PyDict_Next(modules, &pos, &key, &value)) { - if (value->ob_refcnt != 1) - continue; - if (PyUnicode_Check(key) && PyModule_Check(value)) { - if (is_essential_module(key)) - continue; - if (Py_VerboseFlag) - PySys_FormatStderr( - "# cleanup[1] %U\n", key); - _PyModule_Clear(value); - PyDict_SetItem(modules, key, Py_None); - ndone++; - } - } - } while (ndone > 0); - - /* Next, delete all modules (still skipping builtins and sys) */ + /* Remove all modules from sys.modules, hoping that garbage collection + can reclaim most of them. */ pos = 0; while (PyDict_Next(modules, &pos, &key, &value)) { - if (PyUnicode_Check(key) && PyModule_Check(value)) { - if (is_essential_module(key)) - continue; - if (Py_VerboseFlag) - PySys_FormatStderr("# cleanup[2] %U\n", key); - _PyModule_Clear(value); + if (PyModule_Check(value)) { + if (Py_VerboseFlag && PyUnicode_Check(key)) + PySys_FormatStderr("# cleanup[2] removing %U\n", key, value); + STORE_MODULE_WEAKREF(value); PyDict_SetItem(modules, key, Py_None); } } - /* Collect garbage remaining after deleting the modules. Mostly - reference cycles created by classes. */ - PyGC_Collect(); - + /* Clear the modules dict. */ + PyDict_Clear(modules); + /* Replace the interpreter's reference to builtins with an empty dict + (module globals still have a reference to the original builtins). */ + builtins = interp->builtins; + interp->builtins = PyDict_New(); + Py_DECREF(builtins); + /* Collect references */ + _PyGC_CollectNoFail(); /* Dump GC stats before it's too late, since it uses the warnings machinery. */ _PyGC_DumpShutdownStats(); - /* Next, delete all remaining modules */ - pos = 0; - while (PyDict_Next(modules, &pos, &key, &value)) { - if (PyUnicode_Check(key) && PyModule_Check(value)) { + /* Now, if there are any modules left alive, clear their globals to + minimize potential leaks. All C extension modules actually end + up here, since they are kept alive in the interpreter state. */ + if (weaklist != NULL) { + Py_ssize_t i, n; + n = PyList_GET_SIZE(weaklist); + for (i = 0; i < n; i++) { + PyObject *tup = PyList_GET_ITEM(weaklist, i); + PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1)); + if (mod == Py_None) + continue; + Py_INCREF(mod); + assert(PyModule_Check(mod)); if (Py_VerboseFlag) - PySys_FormatStderr("# cleanup[3] %U\n", key); - _PyModule_Clear(value); - PyDict_SetItem(modules, key, Py_None); + PySys_FormatStderr("# cleanup[3] wiping %U\n", + PyTuple_GET_ITEM(tup, 0), mod); + _PyModule_Clear(mod); + Py_DECREF(mod); } + Py_DECREF(weaklist); } - /* Finally, clear and delete the modules directory */ - PyDict_Clear(modules); - _PyGC_CollectNoFail(); + /* Clear and delete the modules directory. Actual modules will + still be there only if imported during the execution of some + destructor. */ interp->modules = NULL; Py_DECREF(modules); + + /* Once more */ + _PyGC_CollectNoFail(); + +#undef STORE_MODULE_WEAKREF } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 23:15:47 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 31 Jul 2013 23:15:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_whitespace?= Message-ID: <3c56ql5yQ1zSPp@mail.python.org> http://hg.python.org/cpython/rev/809a64ecd5f1 changeset: 84937:809a64ecd5f1 user: Antoine Pitrou date: Wed Jul 31 23:15:37 2013 +0200 summary: Fix whitespace files: Lib/rlcompleter.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -163,4 +163,3 @@ # contents are quasi-immortal, and the completer function holds a # reference to globals). atexit.register(lambda: readline.set_completer(None)) - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 23:50:17 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 23:50:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Silence_warnin?= =?utf-8?q?g_about_set_but_unused_variable_inside_compile=5Fatom=28=29_in?= Message-ID: <3c57bY1F62zPsJ@mail.python.org> http://hg.python.org/cpython/rev/83a55ca935f0 changeset: 84938:83a55ca935f0 branch: 3.3 parent: 84908:9bf89c909bd4 user: Christian Heimes date: Wed Jul 31 23:47:56 2013 +0200 summary: Silence warning about set but unused variable inside compile_atom() in non-debug builds files: Parser/pgen.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Parser/pgen.c b/Parser/pgen.c --- a/Parser/pgen.c +++ b/Parser/pgen.c @@ -283,6 +283,7 @@ REQ(n, ATOM); i = n->n_nchildren; + (void)i; /* Don't warn about set but unused */ REQN(i, 1); n = n->n_child; if (n->n_type == LPAR) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 23:50:18 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 23:50:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Silence_warning_about_set_but_unused_variable_inside_com?= =?utf-8?q?pile=5Fatom=28=29_in?= Message-ID: <3c57bZ3BgyzPsJ@mail.python.org> http://hg.python.org/cpython/rev/0e09588a3bc2 changeset: 84939:0e09588a3bc2 parent: 84937:809a64ecd5f1 parent: 84938:83a55ca935f0 user: Christian Heimes date: Wed Jul 31 23:48:04 2013 +0200 summary: Silence warning about set but unused variable inside compile_atom() in non-debug builds files: Parser/pgen.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Parser/pgen.c b/Parser/pgen.c --- a/Parser/pgen.c +++ b/Parser/pgen.c @@ -283,6 +283,7 @@ REQ(n, ATOM); i = n->n_nchildren; + (void)i; /* Don't warn about set but unused */ REQN(i, 1); n = n->n_child; if (n->n_type == LPAR) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 23:50:19 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 23:50:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_merge?= Message-ID: <3c57bb6LklzS0N@mail.python.org> http://hg.python.org/cpython/rev/e1816ec67143 changeset: 84940:e1816ec67143 branch: 3.3 parent: 84938:83a55ca935f0 parent: 84926:366beee880aa user: Christian Heimes date: Wed Jul 31 23:49:48 2013 +0200 summary: merge files: Doc/extending/newtypes.rst | 9 ++++----- Doc/library/difflib.rst | 2 +- Doc/library/email.iterators.rst | 2 +- Doc/library/email.policy.rst | 2 +- Doc/library/unittest.rst | 6 +++--- Doc/tutorial/inputoutput.rst | 13 +++++++++---- Makefile.pre.in | 2 +- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -962,10 +962,9 @@ if (self->my_callback != NULL) { PyObject *err_type, *err_value, *err_traceback; - int have_error = PyErr_Occurred() ? 1 : 0; - if (have_error) - PyErr_Fetch(&err_type, &err_value, &err_traceback); + /* This saves the current exception state */ + PyErr_Fetch(&err_type, &err_value, &err_traceback); cbresult = PyObject_CallObject(self->my_callback, NULL); if (cbresult == NULL) @@ -973,8 +972,8 @@ else Py_DECREF(cbresult); - if (have_error) - PyErr_Restore(err_type, err_value, err_traceback); + /* This restores the saved exception state */ + PyErr_Restore(err_type, err_value, err_traceback); Py_DECREF(self->my_callback); } diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -752,7 +752,7 @@ # we're passing these as arguments to the diff function fromdate = time.ctime(os.stat(fromfile).st_mtime) todate = time.ctime(os.stat(tofile).st_mtime) - with open(fromlines) as fromf, open(tofile) as tof: + with open(fromfile) as fromf, open(tofile) as tof: fromlines, tolines = list(fromf), list(tof) if options.u: diff --git a/Doc/library/email.iterators.rst b/Doc/library/email.iterators.rst --- a/Doc/library/email.iterators.rst +++ b/Doc/library/email.iterators.rst @@ -68,7 +68,7 @@ text/plain text/plain - .. testcleanup:: + .. testsetup:: >>> somefile.close() diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -85,7 +85,7 @@ >>> p.stdin.close() >>> rc = p.wait() -.. testcleanup:: +.. testsetup:: >>> mymsg.close() >>> mocker.stop() diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -897,12 +897,12 @@ Test that a warning is triggered when *callable* is called with any positional or keyword arguments that are also passed to :meth:`assertWarns`. The test passes if *warning* is triggered and - fails if it isn't. Also, any unexpected exception is an error. + fails if it isn't. Any exception is an error. To catch any of a group of warnings, a tuple containing the warning classes may be passed as *warnings*. If only the *warning* and possibly the *msg* arguments are given, - returns a context manager so that the code under test can be written + return a context manager so that the code under test can be written inline rather than as a function:: with self.assertWarns(SomeWarning): @@ -915,7 +915,7 @@ :attr:`warning` attribute, and the source line which triggered the warnings in the :attr:`filename` and :attr:`lineno` attributes. This can be useful if the intention is to perform additional checks - on the exception raised:: + on the warning caught:: with self.assertWarns(SomeWarning) as cm: do_something() diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -322,9 +322,11 @@ >>> f.write(s) 18 -``f.tell()`` returns an integer giving the file object's current position in the -file, measured in bytes from the beginning of the file. To change the file -object's position, use ``f.seek(offset, from_what)``. The position is computed +``f.tell()`` returns an integer giving the file object's current position in the file +represented as number of bytes from the beginning of the file when in `binary mode` and +an opaque number when in `text mode`. + +To change the file object's position, use ``f.seek(offset, from_what)``. The position is computed from adding *offset* to a reference point; the reference point is selected by the *from_what* argument. A *from_what* value of 0 measures from the beginning of the file, 1 uses the current file position, and 2 uses the end of the file as @@ -345,7 +347,10 @@ In text files (those opened without a ``b`` in the mode string), only seeks relative to the beginning of the file are allowed (the exception being seeking -to the very file end with ``seek(0, 2)``). +to the very file end with ``seek(0, 2)``) and the only valid *offset* values are +those returned from the ``f.tell()``, or zero. Any other *offset* value produces +undefined behaviour. + When you're done with a file, call ``f.close()`` to close it and free up any system resources taken up by the open file. After calling ``f.close()``, diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1012,7 +1012,7 @@ tkinter/test/test_ttk site-packages test \ test/capath test/data \ test/cjkencodings test/decimaltestdata test/xmltestdata \ - test/subprocessdata test/sndhdrdata \ + test/subprocessdata test/sndhdrdata test/support \ test/tracedmodules test/encoded_modules \ test/namespace_pkgs \ test/namespace_pkgs/both_portions \ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 31 23:50:21 2013 From: python-checkins at python.org (christian.heimes) Date: Wed, 31 Jul 2013 23:50:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3c57bd129kzS0N@mail.python.org> http://hg.python.org/cpython/rev/d5cf4f973602 changeset: 84941:d5cf4f973602 parent: 84939:0e09588a3bc2 parent: 84940:e1816ec67143 user: Christian Heimes date: Wed Jul 31 23:50:03 2013 +0200 summary: merge files: -- Repository URL: http://hg.python.org/cpython