From python-checkins at python.org Wed Jul 1 00:19:31 2015 From: python-checkins at python.org (yury.selivanov) Date: Tue, 30 Jun 2015 22:19:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NDAw?= =?utf-8?q?=3A_Remove_inspect=2Eisawaitable=28=29=2E?= Message-ID: <20150630221931.26909.28513@psf.io> https://hg.python.org/cpython/rev/e20c197f19d6 changeset: 96728:e20c197f19d6 branch: 3.5 parent: 96726:73c7d29a8c10 user: Yury Selivanov date: Tue Jun 30 18:19:01 2015 -0400 summary: Issue #24400: Remove inspect.isawaitable(). isawaitable() was added before collections.abc.Awaitable; now, with Awaitable, it is no longer needed (we don't have ishashable() or isiterable() methods in the inspect module either). files: Doc/library/inspect.rst | 10 ---------- Doc/whatsnew/3.5.rst | 5 ++--- Lib/inspect.py | 4 ---- Lib/test/test_inspect.py | 25 ------------------------- 4 files changed, 2 insertions(+), 42 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -303,16 +303,6 @@ .. versionadded:: 3.5 -.. function:: isawaitable(object) - - Return true if the object can be used in :keyword:`await` - expression. - - See also :class:`collections.abc.Awaitable`. - - .. versionadded:: 3.5 - - .. function:: istraceback(object) Return true if the object is a traceback. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -527,9 +527,8 @@ * New argument ``follow_wrapped`` for :func:`inspect.signature`. (Contributed by Yury Selivanov in :issue:`20691`.) -* New :func:`~inspect.iscoroutine`, :func:`~inspect.iscoroutinefunction`, - and :func:`~inspect.isawaitable` functions. (Contributed by Yury Selivanov - in :issue:`24017`.) +* New :func:`~inspect.iscoroutine` and :func:`~inspect.iscoroutinefunction` + functions. (Contributed by Yury Selivanov in :issue:`24017`.) * New :func:`~inspect.getcoroutinelocals` and :func:`~inspect.getcoroutinestate` functions. (Contributed by Yury Selivanov in :issue:`24400`.) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -186,10 +186,6 @@ return bool((isfunction(object) or ismethod(object)) and object.__code__.co_flags & CO_COROUTINE) -def isawaitable(object): - """Return true if the object can be used in "await" expression.""" - return isinstance(object, collections.abc.Awaitable) - def isgenerator(object): """Return true if the object is a generator. 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 @@ -159,31 +159,6 @@ coro.close(); gen_coro.close() # silence warnings - def test_isawaitable(self): - def gen(): yield - self.assertFalse(inspect.isawaitable(gen())) - - coro = coroutine_function_example(1) - gen_coro = gen_coroutine_function_example(1) - - self.assertTrue( - inspect.isawaitable(coro)) - self.assertTrue( - inspect.isawaitable(gen_coro)) - - class Future: - def __await__(): - pass - self.assertTrue(inspect.isawaitable(Future())) - self.assertFalse(inspect.isawaitable(Future)) - - class NotFuture: pass - not_fut = NotFuture() - not_fut.__await__ = lambda: None - self.assertFalse(inspect.isawaitable(not_fut)) - - coro.close(); gen_coro.close() # silence warnings - def test_isroutine(self): self.assertTrue(inspect.isroutine(mod.spam)) self.assertTrue(inspect.isroutine([].count)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 00:19:33 2015 From: python-checkins at python.org (yury.selivanov) Date: Tue, 30 Jun 2015 22:19:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChJc3N1ZSAjMjQ0MDAp?= Message-ID: <20150630221931.13084.4339@psf.io> https://hg.python.org/cpython/rev/800bf6a0e0d5 changeset: 96729:800bf6a0e0d5 parent: 96727:5d43f103f66b parent: 96728:e20c197f19d6 user: Yury Selivanov date: Tue Jun 30 18:19:18 2015 -0400 summary: Merge 3.5 (Issue #24400) files: Doc/library/inspect.rst | 10 ---------- Doc/whatsnew/3.5.rst | 5 ++--- Lib/inspect.py | 4 ---- Lib/test/test_inspect.py | 25 ------------------------- 4 files changed, 2 insertions(+), 42 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -303,16 +303,6 @@ .. versionadded:: 3.5 -.. function:: isawaitable(object) - - Return true if the object can be used in :keyword:`await` - expression. - - See also :class:`collections.abc.Awaitable`. - - .. versionadded:: 3.5 - - .. function:: istraceback(object) Return true if the object is a traceback. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -527,9 +527,8 @@ * New argument ``follow_wrapped`` for :func:`inspect.signature`. (Contributed by Yury Selivanov in :issue:`20691`.) -* New :func:`~inspect.iscoroutine`, :func:`~inspect.iscoroutinefunction`, - and :func:`~inspect.isawaitable` functions. (Contributed by Yury Selivanov - in :issue:`24017`.) +* New :func:`~inspect.iscoroutine` and :func:`~inspect.iscoroutinefunction` + functions. (Contributed by Yury Selivanov in :issue:`24017`.) * New :func:`~inspect.getcoroutinelocals` and :func:`~inspect.getcoroutinestate` functions. (Contributed by Yury Selivanov in :issue:`24400`.) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -186,10 +186,6 @@ return bool((isfunction(object) or ismethod(object)) and object.__code__.co_flags & CO_COROUTINE) -def isawaitable(object): - """Return true if the object can be used in "await" expression.""" - return isinstance(object, collections.abc.Awaitable) - def isgenerator(object): """Return true if the object is a generator. 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 @@ -159,31 +159,6 @@ coro.close(); gen_coro.close() # silence warnings - def test_isawaitable(self): - def gen(): yield - self.assertFalse(inspect.isawaitable(gen())) - - coro = coroutine_function_example(1) - gen_coro = gen_coroutine_function_example(1) - - self.assertTrue( - inspect.isawaitable(coro)) - self.assertTrue( - inspect.isawaitable(gen_coro)) - - class Future: - def __await__(): - pass - self.assertTrue(inspect.isawaitable(Future())) - self.assertFalse(inspect.isawaitable(Future)) - - class NotFuture: pass - not_fut = NotFuture() - not_fut.__await__ = lambda: None - self.assertFalse(inspect.isawaitable(not_fut)) - - coro.close(); gen_coro.close() # silence warnings - def test_isroutine(self): self.assertTrue(inspect.isroutine(mod.spam)) self.assertTrue(inspect.isroutine([].count)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 00:26:00 2015 From: python-checkins at python.org (yury.selivanov) Date: Tue, 30 Jun 2015 22:26:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChORVdTKQ==?= Message-ID: <20150630222559.89409.14689@psf.io> https://hg.python.org/cpython/rev/e858afe55ce9 changeset: 96731:e858afe55ce9 parent: 96729:800bf6a0e0d5 parent: 96730:f22a0358418e user: Yury Selivanov date: Tue Jun 30 18:25:55 2015 -0400 summary: Merge 3.5 (NEWS) files: Misc/NEWS | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,7 +46,8 @@ works only for 'async def' coroutines; inspect.iscoroutine no longer uses collections.abc.Coroutine, it's intended to test for pure 'async def' coroutines only; add new opcode: GET_YIELD_FROM_ITER; fix generators wrapper - used in types.coroutine to be instance of collections.abc.Generator. + used in types.coroutine to be instance of collections.abc.Generator; + inspect.isawaitable was removed (use collections.abc.Awaitable). Library ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 00:26:01 2015 From: python-checkins at python.org (yury.selivanov) Date: Tue, 30 Jun 2015 22:26:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Note_removal_o?= =?utf-8?q?f_inspect=2Eisawaitable=28=29_in_the_NEWS_file?= Message-ID: <20150630222558.106268.14502@psf.io> https://hg.python.org/cpython/rev/f22a0358418e changeset: 96730:f22a0358418e branch: 3.5 parent: 96728:e20c197f19d6 user: Yury Selivanov date: Tue Jun 30 18:25:36 2015 -0400 summary: Note removal of inspect.isawaitable() in the NEWS file files: Misc/NEWS | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,7 +24,8 @@ works only for 'async def' coroutines; inspect.iscoroutine no longer uses collections.abc.Coroutine, it's intended to test for pure 'async def' coroutines only; add new opcode: GET_YIELD_FROM_ITER; fix generators wrapper - used in types.coroutine to be instance of collections.abc.Generator. + used in types.coroutine to be instance of collections.abc.Generator; + inspect.isawaitable was removed (use collections.abc.Awaitable). Library ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 00:30:45 2015 From: python-checkins at python.org (yury.selivanov) Date: Tue, 30 Jun 2015 22:30:45 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_pep-0492=3A_inspect=2Eisawait?= =?utf-8?q?able_is_dead=2C_long_live_abc=2EAwaitable=2E?= Message-ID: <20150630223045.20146.68534@psf.io> https://hg.python.org/peps/rev/201dce690493 changeset: 5901:201dce690493 user: Yury Selivanov date: Tue Jun 30 18:30:43 2015 -0400 summary: pep-0492: inspect.isawaitable is dead, long live abc.Awaitable. files: pep-0492.txt | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pep-0492.txt b/pep-0492.txt --- a/pep-0492.txt +++ b/pep-0492.txt @@ -701,9 +701,6 @@ * ``inspect.iscoroutinefunction(obj)`` returns ``True`` if ``obj`` is a *native coroutine function*. -* ``inspect.isawaitable(obj)`` returns ``True`` if ``obj`` can be used - in ``await`` expression. See `Await Expression`_ for details. - * ``inspect.getcoroutinestate(coro)`` returns the current state of a *native coroutine object* (mirrors ``inspect.getfgeneratorstate(gen)``). @@ -1360,8 +1357,8 @@ 6. New functions: ``sys.set_coroutine_wrapper(callback)``, ``sys.get_coroutine_wrapper()``, ``types.coroutine(gen)``, ``inspect.iscoroutinefunction(func)``, ``inspect.iscoroutine(obj)``, - ``inspect.isawaitable(obj)``, ``inspect.getcoroutinestate(coro)``, - and ``inspect.getcoroutinelocals(coro)``. + ``inspect.getcoroutinestate(coro)``, and + ``inspect.getcoroutinelocals(coro)``. 7. New ``CO_COROUTINE`` and ``CO_ITERABLE_COROUTINE`` bit flags for code objects. -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Jul 1 03:19:04 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 01:19:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NDAw?= =?utf-8?q?=3A_Fix_failing_unittest?= Message-ID: <20150701011904.28405.67573@psf.io> https://hg.python.org/cpython/rev/0b7c313851ca changeset: 96732:0b7c313851ca branch: 3.5 parent: 96730:f22a0358418e user: Yury Selivanov date: Tue Jun 30 21:18:27 2015 -0400 summary: Issue #24400: Fix failing unittest files: Lib/test/test_inspect.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -95,7 +95,7 @@ count = len([x for x in dir(inspect) if x.startswith('is')]) # This test is here for remember you to update Doc/library/inspect.rst # which claims there are 16 such functions - expected = 19 + expected = 18 err_msg = "There are %d (not %d) is* functions" % (count, expected) self.assertEqual(count, expected, err_msg) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 03:19:04 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 01:19:04 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChJc3N1ZSAjMjQ0MDAp?= Message-ID: <20150701011904.87143.48454@psf.io> https://hg.python.org/cpython/rev/8c85291e86bf changeset: 96733:8c85291e86bf parent: 96731:e858afe55ce9 parent: 96732:0b7c313851ca user: Yury Selivanov date: Tue Jun 30 21:19:00 2015 -0400 summary: Merge 3.5 (Issue #24400) files: Lib/test/test_inspect.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -95,7 +95,7 @@ count = len([x for x in dir(inspect) if x.startswith('is')]) # This test is here for remember you to update Doc/library/inspect.rst # which claims there are 16 such functions - expected = 19 + expected = 18 err_msg = "There are %d (not %d) is* functions" % (count, expected) self.assertEqual(count, expected, err_msg) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 03:45:19 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 01:45:19 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NTQx?= =?utf-8?q?=3A_Update_comment_in_test=5Finspect=2Etest=5Feightteen?= Message-ID: <20150701014519.12875.31802@psf.io> https://hg.python.org/cpython/rev/a5c6eaa7d733 changeset: 96734:a5c6eaa7d733 branch: 3.5 parent: 96732:0b7c313851ca user: Yury Selivanov date: Tue Jun 30 21:44:52 2015 -0400 summary: Issue #24541: Update comment in test_inspect.test_eightteen files: Lib/test/test_inspect.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -94,7 +94,7 @@ def test_eightteen(self): count = len([x for x in dir(inspect) if x.startswith('is')]) # This test is here for remember you to update Doc/library/inspect.rst - # which claims there are 16 such functions + # which claims there are 18 such functions expected = 18 err_msg = "There are %d (not %d) is* functions" % (count, expected) self.assertEqual(count, expected, err_msg) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 03:45:20 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 01:45:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41?= Message-ID: <20150701014519.65316.78685@psf.io> https://hg.python.org/cpython/rev/df310e5ac015 changeset: 96735:df310e5ac015 parent: 96733:8c85291e86bf parent: 96734:a5c6eaa7d733 user: Yury Selivanov date: Tue Jun 30 21:45:03 2015 -0400 summary: Merge 3.5 files: Lib/test/test_inspect.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -94,7 +94,7 @@ def test_eightteen(self): count = len([x for x in dir(inspect) if x.startswith('is')]) # This test is here for remember you to update Doc/library/inspect.rst - # which claims there are 16 such functions + # which claims there are 18 such functions expected = 18 err_msg = "There are %d (not %d) is* functions" % (count, expected) self.assertEqual(count, expected, err_msg) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 04:07:00 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 02:07:00 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NTQx?= =?utf-8?q?=3A_Drop_test=5Finspect=2Etest=5Feightteen_unittest=3B_update_d?= =?utf-8?q?ocs?= Message-ID: <20150701020700.21113.41052@psf.io> https://hg.python.org/cpython/rev/bd45435fd081 changeset: 96736:bd45435fd081 branch: 3.5 parent: 96734:a5c6eaa7d733 user: Yury Selivanov date: Tue Jun 30 22:06:42 2015 -0400 summary: Issue #24541: Drop test_inspect.test_eightteen unittest; update docs Suggested by Martin Panter. files: Doc/library/inspect.rst | 2 +- Lib/test/test_inspect.py | 8 -------- 2 files changed, 1 insertions(+), 9 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -28,7 +28,7 @@ ----------------- The :func:`getmembers` function retrieves the members of an object such as a -class or module. The sixteen functions whose names begin with "is" are mainly +class or module. The functions whose names begin with "is" are mainly provided as convenient choices for the second argument to :func:`getmembers`. They also help you determine when you can expect to find the following special attributes: 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 @@ -91,14 +91,6 @@ class TestPredicates(IsTestBase): - def test_eightteen(self): - count = len([x for x in dir(inspect) if x.startswith('is')]) - # This test is here for remember you to update Doc/library/inspect.rst - # which claims there are 18 such functions - expected = 18 - err_msg = "There are %d (not %d) is* functions" % (count, expected) - self.assertEqual(count, expected, err_msg) - def test_excluding_predicates(self): global tb -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 04:07:01 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 02:07:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41?= Message-ID: <20150701020700.24410.70095@psf.io> https://hg.python.org/cpython/rev/1b87b31434d8 changeset: 96737:1b87b31434d8 parent: 96735:df310e5ac015 parent: 96736:bd45435fd081 user: Yury Selivanov date: Tue Jun 30 22:06:55 2015 -0400 summary: Merge 3.5 files: Doc/library/inspect.rst | 2 +- Lib/test/test_inspect.py | 8 -------- 2 files changed, 1 insertions(+), 9 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -28,7 +28,7 @@ ----------------- The :func:`getmembers` function retrieves the members of an object such as a -class or module. The sixteen functions whose names begin with "is" are mainly +class or module. The functions whose names begin with "is" are mainly provided as convenient choices for the second argument to :func:`getmembers`. They also help you determine when you can expect to find the following special attributes: 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 @@ -91,14 +91,6 @@ class TestPredicates(IsTestBase): - def test_eightteen(self): - count = len([x for x in dir(inspect) if x.startswith('is')]) - # This test is here for remember you to update Doc/library/inspect.rst - # which claims there are 18 such functions - expected = 18 - err_msg = "There are %d (not %d) is* functions" % (count, expected) - self.assertEqual(count, expected, err_msg) - def test_excluding_predicates(self): global tb -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 04:14:13 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 02:14:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChJc3N1ZSAjMjQ0ODcp?= Message-ID: <20150701021413.27321.88841@psf.io> https://hg.python.org/cpython/rev/3dc2a113e8a7 changeset: 96739:3dc2a113e8a7 parent: 96737:1b87b31434d8 parent: 96738:1b3be273e327 user: Yury Selivanov date: Tue Jun 30 22:13:56 2015 -0400 summary: Merge 3.5 (Issue #24487) files: Doc/library/asyncio-dev.rst | 12 ++++++------ Doc/library/asyncio-eventloop.rst | 2 +- Doc/library/asyncio-protocol.rst | 6 +++--- Doc/library/asyncio-task.rst | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -99,7 +99,7 @@ :meth:`BaseEventLoop.call_soon_threadsafe` method should be used. Example to schedule a coroutine from a different thread:: - loop.call_soon_threadsafe(asyncio.async, coro_func()) + loop.call_soon_threadsafe(asyncio.ensure_future, coro_func()) Most asyncio objects are not thread safe. You should only worry if you access objects outside the event loop. For example, to cancel a future, don't call @@ -162,10 +162,10 @@ ---------------------------------------- When a coroutine function is called and its result is not passed to -:func:`async` or to the :meth:`BaseEventLoop.create_task` method, the execution -of the coroutine object will never be scheduled which is probably a bug. -:ref:`Enable the debug mode of asyncio ` to :ref:`log a -warning ` to detect it. +:func:`ensure_future` or to the :meth:`BaseEventLoop.create_task` method, +the execution of the coroutine object will never be scheduled which is +probably a bug. :ref:`Enable the debug mode of asyncio ` +to :ref:`log a warning ` to detect it. Example with the bug:: @@ -184,7 +184,7 @@ File "test.py", line 7, in test() -The fix is to call the :func:`async` function or the +The fix is to call the :func:`ensure_future` function or the :meth:`BaseEventLoop.create_task` method with the coroutine object. .. seealso:: diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -36,7 +36,7 @@ Run until the :class:`Future` is done. If the argument is a :ref:`coroutine object `, it is wrapped by - :func:`async`. + :func:`ensure_future`. Return the Future's result, or raise its exception. diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -448,9 +448,9 @@ Coroutines and protocols ------------------------ -Coroutines can be scheduled in a protocol method using :func:`async`, but there -is no guarantee made about the execution order. Protocols are not aware of -coroutines created in protocol methods and so will not wait for them. +Coroutines can be scheduled in a protocol method using :func:`ensure_future`, +but there is no guarantee made about the execution order. Protocols are not +aware of coroutines created in protocol methods and so will not wait for them. To have a reliable execution order, use :ref:`stream objects ` in a coroutine with ``yield from``. For example, the :meth:`StreamWriter.drain` diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -59,7 +59,7 @@ schedule its execution. There are two basic ways to start it running: call ``await coroutine`` or ``yield from coroutine`` from another coroutine (assuming the other coroutine is already running!), or schedule its execution -using the :func:`async` function or the :meth:`BaseEventLoop.create_task` +using the :func:`ensure_future` function or the :meth:`BaseEventLoop.create_task` method. @@ -85,7 +85,7 @@ even if they are plain Python functions returning a :class:`Future`. This is intentional to have a freedom of tweaking the implementation of these functions in the future. If such a function is needed to be - used in a callback-style code, wrap its result with :func:`async`. + used in a callback-style code, wrap its result with :func:`ensure_future`. .. _asyncio-hello-world-coroutine: @@ -394,7 +394,7 @@ ` did not complete. It is probably a bug and a warning is logged: see :ref:`Pending task destroyed `. - Don't directly create :class:`Task` instances: use the :func:`async` + Don't directly create :class:`Task` instances: use the :func:`ensure_future` function or the :meth:`BaseEventLoop.create_task` method. This class is :ref:`not thread safe `. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 04:14:13 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 02:14:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NDg3?= =?utf-8?q?=3A_Rename_async=28=29_-=3E_ensure=5Ffuture=28=29_in_asyncio_do?= =?utf-8?b?Y3Mu?= Message-ID: <20150701021412.85260.26502@psf.io> https://hg.python.org/cpython/rev/1b3be273e327 changeset: 96738:1b3be273e327 branch: 3.5 parent: 96736:bd45435fd081 user: Yury Selivanov date: Tue Jun 30 22:13:22 2015 -0400 summary: Issue #24487: Rename async() -> ensure_future() in asyncio docs. Patch by Martin Panter. files: Doc/library/asyncio-dev.rst | 12 ++++++------ Doc/library/asyncio-eventloop.rst | 2 +- Doc/library/asyncio-protocol.rst | 6 +++--- Doc/library/asyncio-task.rst | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -99,7 +99,7 @@ :meth:`BaseEventLoop.call_soon_threadsafe` method should be used. Example to schedule a coroutine from a different thread:: - loop.call_soon_threadsafe(asyncio.async, coro_func()) + loop.call_soon_threadsafe(asyncio.ensure_future, coro_func()) Most asyncio objects are not thread safe. You should only worry if you access objects outside the event loop. For example, to cancel a future, don't call @@ -162,10 +162,10 @@ ---------------------------------------- When a coroutine function is called and its result is not passed to -:func:`async` or to the :meth:`BaseEventLoop.create_task` method, the execution -of the coroutine object will never be scheduled which is probably a bug. -:ref:`Enable the debug mode of asyncio ` to :ref:`log a -warning ` to detect it. +:func:`ensure_future` or to the :meth:`BaseEventLoop.create_task` method, +the execution of the coroutine object will never be scheduled which is +probably a bug. :ref:`Enable the debug mode of asyncio ` +to :ref:`log a warning ` to detect it. Example with the bug:: @@ -184,7 +184,7 @@ File "test.py", line 7, in test() -The fix is to call the :func:`async` function or the +The fix is to call the :func:`ensure_future` function or the :meth:`BaseEventLoop.create_task` method with the coroutine object. .. seealso:: diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -36,7 +36,7 @@ Run until the :class:`Future` is done. If the argument is a :ref:`coroutine object `, it is wrapped by - :func:`async`. + :func:`ensure_future`. Return the Future's result, or raise its exception. diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -448,9 +448,9 @@ Coroutines and protocols ------------------------ -Coroutines can be scheduled in a protocol method using :func:`async`, but there -is no guarantee made about the execution order. Protocols are not aware of -coroutines created in protocol methods and so will not wait for them. +Coroutines can be scheduled in a protocol method using :func:`ensure_future`, +but there is no guarantee made about the execution order. Protocols are not +aware of coroutines created in protocol methods and so will not wait for them. To have a reliable execution order, use :ref:`stream objects ` in a coroutine with ``yield from``. For example, the :meth:`StreamWriter.drain` diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -59,7 +59,7 @@ schedule its execution. There are two basic ways to start it running: call ``await coroutine`` or ``yield from coroutine`` from another coroutine (assuming the other coroutine is already running!), or schedule its execution -using the :func:`async` function or the :meth:`BaseEventLoop.create_task` +using the :func:`ensure_future` function or the :meth:`BaseEventLoop.create_task` method. @@ -85,7 +85,7 @@ even if they are plain Python functions returning a :class:`Future`. This is intentional to have a freedom of tweaking the implementation of these functions in the future. If such a function is needed to be - used in a callback-style code, wrap its result with :func:`async`. + used in a callback-style code, wrap its result with :func:`ensure_future`. .. _asyncio-hello-world-coroutine: @@ -394,7 +394,7 @@ ` did not complete. It is probably a bug and a warning is logged: see :ref:`Pending task destroyed `. - Don't directly create :class:`Task` instances: use the :func:`async` + Don't directly create :class:`Task` instances: use the :func:`ensure_future` function or the :meth:`BaseEventLoop.create_task` method. This class is :ref:`not thread safe `. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Wed Jul 1 10:46:03 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 01 Jul 2015 08:46:03 +0000 Subject: [Python-checkins] Daily reference leaks (3dc2a113e8a7): sum=7 Message-ID: <20150701084603.3300.75405@psf.io> results for 3dc2a113e8a7 on branch "default" -------------------------------------------- test_asyncio leaked [0, 0, 3] memory blocks, sum=3 test_functools leaked [0, 2, 2] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogrt3cUA', '--timeout', '7200'] From python-checkins at python.org Wed Jul 1 17:31:57 2015 From: python-checkins at python.org (donald.stufft) Date: Wed, 01 Jul 2015 15:31:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Update_setupto?= =?utf-8?q?ols_to_18=2E0=2E1_and_pip_to_7=2E1=2E0?= Message-ID: <20150701153153.109639.79609@psf.io> https://hg.python.org/cpython/rev/814965258782 changeset: 96741:814965258782 branch: 3.4 parent: 96721:75571407dcd3 user: Donald Stufft date: Wed Jul 01 11:30:50 2015 -0400 summary: Update setuptools to 18.0.1 and pip to 7.1.0 files: Lib/ensurepip/__init__.py | 4 ++-- Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl | Bin 5 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -8,9 +8,9 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "17.0" +_SETUPTOOLS_VERSION = "18.0.1" -_PIP_VERSION = "7.0.3" +_PIP_VERSION = "7.1.0" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl deleted file mode 100644 index bb0cb3138ba4ade7fa5ba3285d04f70d439f490f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..76fcad1c7efb6223b049967e84fda31f9fd68dfc GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl deleted file mode 100644 index a1d3561bad9c3709196b6481dd2e540b0914129b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..67aaca50a921a164fac7d721bc2aa80735c5515e GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 17:44:59 2015 From: python-checkins at python.org (donald.stufft) Date: Wed, 01 Jul 2015 15:44:59 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_merge_in_setuptools/pip_update?= Message-ID: <20150701153153.14971.69049@psf.io> https://hg.python.org/cpython/rev/5d1e16be1af6 changeset: 96742:5d1e16be1af6 branch: 3.5 parent: 96738:1b3be273e327 parent: 96741:814965258782 user: Donald Stufft date: Wed Jul 01 11:31:13 2015 -0400 summary: merge in setuptools/pip update files: Lib/ensurepip/__init__.py | 4 ++-- Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl | Bin 5 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -8,9 +8,9 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "17.0" +_SETUPTOOLS_VERSION = "18.0.1" -_PIP_VERSION = "7.0.3" +_PIP_VERSION = "7.1.0" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl deleted file mode 100644 index bb0cb3138ba4ade7fa5ba3285d04f70d439f490f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..76fcad1c7efb6223b049967e84fda31f9fd68dfc GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl deleted file mode 100644 index a1d3561bad9c3709196b6481dd2e540b0914129b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..67aaca50a921a164fac7d721bc2aa80735c5515e GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 18:34:44 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 16:34:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NDAw?= =?utf-8?q?=3A_Add_one_more_unittest_for_CoroutineType=2E=5F=5Fawait=5F=5F?= Message-ID: <20150701163444.18679.67580@psf.io> https://hg.python.org/cpython/rev/a9d38701536d changeset: 96744:a9d38701536d branch: 3.5 parent: 96742:5d1e16be1af6 user: Yury Selivanov date: Wed Jul 01 12:29:55 2015 -0400 summary: Issue #24400: Add one more unittest for CoroutineType.__await__ files: Lib/test/test_coroutines.py | 34 +++++++++++++++++++++++++ 1 files changed, 34 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -519,6 +519,40 @@ run_async(foo()) + def test_await_14(self): + class Wrapper: + # Forces the interpreter to use CoroutineType.__await__ + def __init__(self, coro): + assert coro.__class__ is types.CoroutineType + self.coro = coro + def __await__(self): + return self.coro.__await__() + + class FutureLike: + def __await__(self): + return (yield) + + class Marker(Exception): + pass + + async def coro1(): + try: + return await FutureLike() + except ZeroDivisionError: + raise Marker + async def coro2(): + return await Wrapper(coro1()) + + c = coro2() + c.send(None) + with self.assertRaisesRegex(StopIteration, 'spam'): + c.send('spam') + + c = coro2() + c.send(None) + with self.assertRaises(Marker): + c.throw(ZeroDivisionError) + def test_with_1(self): class Manager: def __init__(self, name): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 18:34:47 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 16:34:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41?= Message-ID: <20150701163444.110093.33140@psf.io> https://hg.python.org/cpython/rev/ac4581bad6ef changeset: 96745:ac4581bad6ef parent: 96743:53975668c9e9 parent: 96744:a9d38701536d user: Yury Selivanov date: Wed Jul 01 12:30:26 2015 -0400 summary: Merge 3.5 files: Lib/test/test_coroutines.py | 34 +++++++++++++++++++++++++ 1 files changed, 34 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -519,6 +519,40 @@ run_async(foo()) + def test_await_14(self): + class Wrapper: + # Forces the interpreter to use CoroutineType.__await__ + def __init__(self, coro): + assert coro.__class__ is types.CoroutineType + self.coro = coro + def __await__(self): + return self.coro.__await__() + + class FutureLike: + def __await__(self): + return (yield) + + class Marker(Exception): + pass + + async def coro1(): + try: + return await FutureLike() + except ZeroDivisionError: + raise Marker + async def coro2(): + return await Wrapper(coro1()) + + c = coro2() + c.send(None) + with self.assertRaisesRegex(StopIteration, 'spam'): + c.send('spam') + + c = coro2() + c.send(None) + with self.assertRaises(Marker): + c.throw(ZeroDivisionError) + def test_with_1(self): class Manager: def __init__(self, name): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 18:49:22 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 16:49:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChpc3N1ZSAjMjQ0MDAp?= Message-ID: <20150701164921.13068.18949@psf.io> https://hg.python.org/cpython/rev/4bf1d332fe73 changeset: 96747:4bf1d332fe73 parent: 96745:ac4581bad6ef parent: 96746:b2a3baa1c2b0 user: Yury Selivanov date: Wed Jul 01 12:49:17 2015 -0400 summary: Merge 3.5 (issue #24400) files: Doc/conf.py | 2 +- Doc/library/collections.abc.rst | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py --- a/Doc/conf.py +++ b/Doc/conf.py @@ -44,7 +44,7 @@ # ----------------------- # Use our custom theme. -html_theme = 'pydoctheme' +html_theme = 'classic' html_theme_path = ['tools'] html_theme_options = {'collapsiblesidebar': True} diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -161,6 +161,12 @@ :term:`Coroutine` objects and instances of the :class:`~collections.abc.Coroutine` ABC are all instances of this ABC. + .. note:: + In CPython, generator-based coroutines are *awaitables*, even though + they do not have an :meth:`__await__` method. This ABC + implements an :meth:`~class.__instancecheck__` method to make them + instances of itself. + .. versionadded:: 3.5 .. class:: Coroutine @@ -172,6 +178,12 @@ :meth:`__await__`. All :class:`Coroutine` instances are also instances of :class:`Awaitable`. See also the definition of :term:`coroutine`. + .. note:: + In CPython, generator-based coroutines are *awaitables* and *coroutines*, + even though they do not have an :meth:`__await__` method. This ABC + implements an :meth:`~class.__instancecheck__` method to make them + instances of itself. + .. versionadded:: 3.5 .. class:: AsyncIterable -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 18:49:22 2015 From: python-checkins at python.org (yury.selivanov) Date: Wed, 01 Jul 2015 16:49:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NDAw?= =?utf-8?q?=3A_Mention_that_=5F=5Finstancecheck=5F=5F_is_used_in_abc=2EAwa?= =?utf-8?q?itable_and?= Message-ID: <20150701164921.13068.11467@psf.io> https://hg.python.org/cpython/rev/b2a3baa1c2b0 changeset: 96746:b2a3baa1c2b0 branch: 3.5 parent: 96744:a9d38701536d user: Yury Selivanov date: Wed Jul 01 12:49:00 2015 -0400 summary: Issue #24400: Mention that __instancecheck__ is used in abc.Awaitable and Coroutine files: Doc/conf.py | 2 +- Doc/library/collections.abc.rst | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py --- a/Doc/conf.py +++ b/Doc/conf.py @@ -44,7 +44,7 @@ # ----------------------- # Use our custom theme. -html_theme = 'pydoctheme' +html_theme = 'classic' html_theme_path = ['tools'] html_theme_options = {'collapsiblesidebar': True} diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -161,6 +161,12 @@ :term:`Coroutine` objects and instances of the :class:`~collections.abc.Coroutine` ABC are all instances of this ABC. + .. note:: + In CPython, generator-based coroutines are *awaitables*, even though + they do not have an :meth:`__await__` method. This ABC + implements an :meth:`~class.__instancecheck__` method to make them + instances of itself. + .. versionadded:: 3.5 .. class:: Coroutine @@ -172,6 +178,12 @@ :meth:`__await__`. All :class:`Coroutine` instances are also instances of :class:`Awaitable`. See also the definition of :term:`coroutine`. + .. note:: + In CPython, generator-based coroutines are *awaitables* and *coroutines*, + even though they do not have an :meth:`__await__` method. This ABC + implements an :meth:`~class.__instancecheck__` method to make them + instances of itself. + .. versionadded:: 3.5 .. class:: AsyncIterable -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 19:04:30 2015 From: python-checkins at python.org (donald.stufft) Date: Wed, 01 Jul 2015 17:04:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_merge_in_setuptools/pip_update?= Message-ID: <20150701153154.130183.97996@psf.io> https://hg.python.org/cpython/rev/53975668c9e9 changeset: 96743:53975668c9e9 parent: 96739:3dc2a113e8a7 parent: 96742:5d1e16be1af6 user: Donald Stufft date: Wed Jul 01 11:31:38 2015 -0400 summary: merge in setuptools/pip update files: Lib/ensurepip/__init__.py | 4 ++-- Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl | Bin 5 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -8,9 +8,9 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "17.0" +_SETUPTOOLS_VERSION = "18.0.1" -_PIP_VERSION = "7.0.3" +_PIP_VERSION = "7.1.0" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl deleted file mode 100644 index bb0cb3138ba4ade7fa5ba3285d04f70d439f490f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..76fcad1c7efb6223b049967e84fda31f9fd68dfc GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl deleted file mode 100644 index a1d3561bad9c3709196b6481dd2e540b0914129b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..67aaca50a921a164fac7d721bc2aa80735c5515e GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 1 22:06:56 2015 From: python-checkins at python.org (donald.stufft) Date: Wed, 01 Jul 2015 20:06:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Update_setupto?= =?utf-8?q?ols_to_18=2E0=2E1_and_pip_to_7=2E1=2E0?= Message-ID: <20150701153153.21513.79899@psf.io> https://hg.python.org/cpython/rev/b295b2286697 changeset: 96740:b295b2286697 branch: 2.7 parent: 96717:a887ce8611d2 user: Donald Stufft date: Wed Jul 01 11:29:34 2015 -0400 summary: Update setuptools to 18.0.1 and pip to 7.1.0 files: Lib/ensurepip/__init__.py | 4 ++-- Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl | Bin 5 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -12,9 +12,9 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "17.0" +_SETUPTOOLS_VERSION = "18.0.1" -_PIP_VERSION = "7.0.3" +_PIP_VERSION = "7.1.0" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl deleted file mode 100644 index bb0cb3138ba4ade7fa5ba3285d04f70d439f490f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..76fcad1c7efb6223b049967e84fda31f9fd68dfc GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl deleted file mode 100644 index a1d3561bad9c3709196b6481dd2e540b0914129b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..67aaca50a921a164fac7d721bc2aa80735c5515e GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 03:07:23 2015 From: python-checkins at python.org (yury.selivanov) Date: Thu, 02 Jul 2015 01:07:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogZG9jcy9jb25mOiBV?= =?utf-8?q?ndo_changes_in_b2a3baa1c2b0=3B_issue_=2324400?= Message-ID: <20150702010723.20146.30295@psf.io> https://hg.python.org/cpython/rev/68996acdec6f changeset: 96748:68996acdec6f branch: 3.5 parent: 96746:b2a3baa1c2b0 user: Yury Selivanov date: Wed Jul 01 21:06:59 2015 -0400 summary: docs/conf: Undo changes in b2a3baa1c2b0; issue #24400 files: Doc/conf.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py --- a/Doc/conf.py +++ b/Doc/conf.py @@ -44,7 +44,7 @@ # ----------------------- # Use our custom theme. -html_theme = 'classic' +html_theme = 'pydoctheme' html_theme_path = ['tools'] html_theme_options = {'collapsiblesidebar': True} -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 03:07:23 2015 From: python-checkins at python.org (yury.selivanov) Date: Thu, 02 Jul 2015 01:07:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41?= Message-ID: <20150702010723.99345.27933@psf.io> https://hg.python.org/cpython/rev/67ae0fd72370 changeset: 96749:67ae0fd72370 parent: 96747:4bf1d332fe73 parent: 96748:68996acdec6f user: Yury Selivanov date: Wed Jul 01 21:07:20 2015 -0400 summary: Merge 3.5 files: Doc/conf.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py --- a/Doc/conf.py +++ b/Doc/conf.py @@ -44,7 +44,7 @@ # ----------------------- # Use our custom theme. -html_theme = 'classic' +html_theme = 'pydoctheme' html_theme_path = ['tools'] html_theme_options = {'collapsiblesidebar': True} -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 05:52:22 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 02 Jul 2015 03:52:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy41?= Message-ID: <20150702033642.36294.21526@psf.io> https://hg.python.org/cpython/rev/dbb4fb46fc1d changeset: 96752:dbb4fb46fc1d parent: 96749:67ae0fd72370 parent: 96751:00d706bebc7b user: Benjamin Peterson date: Wed Jul 01 22:36:37 2015 -0500 summary: merge 3.5 files: Doc/whatsnew/3.4.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -1123,7 +1123,7 @@ .. _whatsnew-multiprocessing-no-fork: On Unix two new :ref:`start methods `, -(``spawn`` and ``forkserver``, have been added for starting processes using +``spawn`` and ``forkserver``, have been added for starting processes using :mod:`multiprocessing`. These make the mixing of processes with threads more robust, and the ``spawn`` method matches the semantics that multiprocessing has always used on Windows. New function -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 05:52:22 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 02 Jul 2015 03:52:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_remove_stray_?= =?utf-8?b?JygnIChjbG9zZXMgIzI0NTQ3KQ==?= Message-ID: <20150702033641.130183.30856@psf.io> https://hg.python.org/cpython/rev/74e75a9aa562 changeset: 96750:74e75a9aa562 branch: 3.4 parent: 96741:814965258782 user: Benjamin Peterson date: Wed Jul 01 22:36:21 2015 -0500 summary: remove stray '(' (closes #24547) files: Doc/whatsnew/3.4.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -1123,7 +1123,7 @@ .. _whatsnew-multiprocessing-no-fork: On Unix two new :ref:`start methods `, -(``spawn`` and ``forkserver``, have been added for starting processes using +``spawn`` and ``forkserver``, have been added for starting processes using :mod:`multiprocessing`. These make the mixing of processes with threads more robust, and the ``spawn`` method matches the semantics that multiprocessing has always used on Windows. New function -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 06:41:41 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 02 Jul 2015 04:41:41 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Merge_3=2E4?= Message-ID: <20150702033641.21568.26594@psf.io> https://hg.python.org/cpython/rev/00d706bebc7b changeset: 96751:00d706bebc7b branch: 3.5 parent: 96748:68996acdec6f parent: 96750:74e75a9aa562 user: Benjamin Peterson date: Wed Jul 01 22:36:29 2015 -0500 summary: Merge 3.4 files: Doc/whatsnew/3.4.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -1123,7 +1123,7 @@ .. _whatsnew-multiprocessing-no-fork: On Unix two new :ref:`start methods `, -(``spawn`` and ``forkserver``, have been added for starting processes using +``spawn`` and ``forkserver``, have been added for starting processes using :mod:`multiprocessing`. These make the mixing of processes with threads more robust, and the ``spawn`` method matches the semantics that multiprocessing has always used on Windows. New function -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Thu Jul 2 10:44:55 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 02 Jul 2015 08:44:55 +0000 Subject: [Python-checkins] Daily reference leaks (dbb4fb46fc1d): sum=4 Message-ID: <20150702084455.28944.88968@psf.io> results for dbb4fb46fc1d on branch "default" -------------------------------------------- test_functools leaked [0, 2, 2] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogutPvOi', '--timeout', '7200'] From python-checkins at python.org Thu Jul 2 19:44:33 2015 From: python-checkins at python.org (lars.gustaebel) Date: Thu, 02 Jul 2015 17:44:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0NTE0?= =?utf-8?q?=3A_tarfile_now_tolerates_number_fields_consisting_of_only_whit?= =?utf-8?q?espace=2E?= Message-ID: <20150702174432.22264.26396@psf.io> https://hg.python.org/cpython/rev/301d7efac3de changeset: 96753:301d7efac3de branch: 2.7 parent: 96740:b295b2286697 user: Lars Gust?bel date: Thu Jul 02 19:37:08 2015 +0200 summary: Issue #24514: tarfile now tolerates number fields consisting of only whitespace. files: Lib/tarfile.py | 2 +- Lib/test/test_tarfile.py | 9 +++++++++ Misc/NEWS | 3 +++ 3 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -186,7 +186,7 @@ # itn() below. if s[0] != chr(0200): try: - n = int(nts(s) or "0", 8) + n = int(nts(s).strip() or "0", 8) except ValueError: raise InvalidHeaderError("invalid header") else: 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 @@ -1566,6 +1566,14 @@ tarinfo.tobuf(tarfile.PAX_FORMAT) +class MiscTest(unittest.TestCase): + + def test_read_number_fields(self): + # Issue 24514: Test if empty number fields are converted to zero. + self.assertEqual(tarfile.nti("\0"), 0) + self.assertEqual(tarfile.nti(" \0"), 0) + + class ContextManagerTest(unittest.TestCase): def test_basic(self): @@ -1730,6 +1738,7 @@ PaxUnicodeTest, AppendTest, LimitsTest, + MiscTest, ContextManagerTest, ] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ Library ------- +- Issue #24514: tarfile now tolerates number fields consisting of only + whitespace. + - Issue #20387: Restore semantic round-trip correctness in tokenize/untokenize for tab-indented blocks. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 19:44:33 2015 From: python-checkins at python.org (lars.gustaebel) Date: Thu, 02 Jul 2015 17:44:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI0NTE0?= =?utf-8?q?=3A_tarfile_now_tolerates_number_fields_consisting_of_only_whit?= =?utf-8?q?espace=2E?= Message-ID: <20150702174433.24661.70056@psf.io> https://hg.python.org/cpython/rev/140b4b7b84bd changeset: 96754:140b4b7b84bd branch: 3.4 parent: 96750:74e75a9aa562 user: Lars Gust?bel date: Thu Jul 02 19:38:38 2015 +0200 summary: Issue #24514: tarfile now tolerates number fields consisting of only whitespace. files: Lib/tarfile.py | 3 ++- Lib/test/test_tarfile.py | 4 ++++ Misc/NEWS | 3 +++ 3 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -178,7 +178,8 @@ n = -(256 ** (len(s) - 1) - n) else: try: - n = int(nts(s, "ascii", "strict") or "0", 8) + s = nts(s, "ascii", "strict") + n = int(s.strip() or "0", 8) except ValueError: raise InvalidHeaderError("invalid header") return n 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 @@ -1842,6 +1842,10 @@ self.assertEqual(tarfile.nti(b"\xff\x00\x00\x00\x00\x00\x00\x00"), -0x100000000000000) + # Issue 24514: Test if empty number fields are converted to zero. + self.assertEqual(tarfile.nti(b"\0"), 0) + self.assertEqual(tarfile.nti(b" \0"), 0) + def test_write_number_fields(self): self.assertEqual(tarfile.itn(1), b"0000001\x00") self.assertEqual(tarfile.itn(0o7777777), b"7777777\x00") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -64,6 +64,9 @@ Library ------- +- Issue #24514: tarfile now tolerates number fields consisting of only + whitespace. + - Issue #19176: Fixed doctype() related bugs in C implementation of ElementTree. A deprecation warning no longer issued by XMLParser subclass with default doctype() method. Direct call of doctype() now issues a warning. Parser's -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 19:44:35 2015 From: python-checkins at python.org (lars.gustaebel) Date: Thu, 02 Jul 2015 17:44:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E5=3A_Issue_=2324514=3A_tarfile_now_tolera?= =?utf-8?q?tes_number_fields_consisting_of?= Message-ID: <20150702174433.12463.10060@psf.io> https://hg.python.org/cpython/rev/08fad9037206 changeset: 96756:08fad9037206 parent: 96752:dbb4fb46fc1d parent: 96755:1692065524cc user: Lars Gust?bel date: Thu Jul 02 19:42:09 2015 +0200 summary: Merge with 3.5: Issue #24514: tarfile now tolerates number fields consisting of only whitespace. files: Lib/tarfile.py | 3 ++- Lib/test/test_tarfile.py | 4 ++++ Misc/NEWS | 3 +++ 3 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -178,7 +178,8 @@ n = -(256 ** (len(s) - 1) - n) else: try: - n = int(nts(s, "ascii", "strict") or "0", 8) + s = nts(s, "ascii", "strict") + n = int(s.strip() or "0", 8) except ValueError: raise InvalidHeaderError("invalid header") return n 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 @@ -1952,6 +1952,10 @@ self.assertEqual(tarfile.nti(b"\xff\x00\x00\x00\x00\x00\x00\x00"), -0x100000000000000) + # Issue 24514: Test if empty number fields are converted to zero. + self.assertEqual(tarfile.nti(b"\0"), 0) + self.assertEqual(tarfile.nti(b" \0"), 0) + def test_write_number_fields(self): self.assertEqual(tarfile.itn(1), b"0000001\x00") self.assertEqual(tarfile.itn(0o7777777), b"7777777\x00") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,9 @@ Library ------- +- Issue #24514: tarfile now tolerates number fields consisting of only + whitespace. + - Issue #19176: Fixed doctype() related bugs in C implementation of ElementTree. A deprecation warning no longer issued by XMLParser subclass with default doctype() method. Direct call of doctype() now issues a warning. Parser's -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 19:44:35 2015 From: python-checkins at python.org (lars.gustaebel) Date: Thu, 02 Jul 2015 17:44:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Merge_with_3=2E4=3A_Issue_=2324514=3A_tarfile_now_tolerates_nu?= =?utf-8?q?mber_fields_consisting_of?= Message-ID: <20150702174433.99807.20489@psf.io> https://hg.python.org/cpython/rev/1692065524cc changeset: 96755:1692065524cc branch: 3.5 parent: 96751:00d706bebc7b parent: 96754:140b4b7b84bd user: Lars Gust?bel date: Thu Jul 02 19:41:03 2015 +0200 summary: Merge with 3.4: Issue #24514: tarfile now tolerates number fields consisting of only whitespace. files: Lib/tarfile.py | 3 ++- Lib/test/test_tarfile.py | 4 ++++ Misc/NEWS | 3 +++ 3 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -178,7 +178,8 @@ n = -(256 ** (len(s) - 1) - n) else: try: - n = int(nts(s, "ascii", "strict") or "0", 8) + s = nts(s, "ascii", "strict") + n = int(s.strip() or "0", 8) except ValueError: raise InvalidHeaderError("invalid header") return n 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 @@ -1952,6 +1952,10 @@ self.assertEqual(tarfile.nti(b"\xff\x00\x00\x00\x00\x00\x00\x00"), -0x100000000000000) + # Issue 24514: Test if empty number fields are converted to zero. + self.assertEqual(tarfile.nti(b"\0"), 0) + self.assertEqual(tarfile.nti(b" \0"), 0) + def test_write_number_fields(self): self.assertEqual(tarfile.itn(1), b"0000001\x00") self.assertEqual(tarfile.itn(0o7777777), b"7777777\x00") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,9 @@ Library ------- +- Issue #24514: tarfile now tolerates number fields consisting of only + whitespace. + - Issue #19176: Fixed doctype() related bugs in C implementation of ElementTree. A deprecation warning no longer issued by XMLParser subclass with default doctype() method. Direct call of doctype() now issues a warning. Parser's -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 20:30:59 2015 From: python-checkins at python.org (stefan.krah) Date: Thu, 02 Jul 2015 18:30:59 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjUgKCMyNDU0Myku?= Message-ID: <20150702183059.2656.70701@psf.io> https://hg.python.org/cpython/rev/8f30776602b4 changeset: 96758:8f30776602b4 parent: 96756:08fad9037206 parent: 96757:2be983173f45 user: Stefan Krah date: Thu Jul 02 20:28:45 2015 +0200 summary: Merge from 3.5 (#24543). files: configure | 15 +++++++++------ configure.ac | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -13397,12 +13397,13 @@ return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : have_gcc_asm_for_x64=yes else have_gcc_asm_for_x64=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x64" >&5 $as_echo "$have_gcc_asm_for_x64" >&6; } if test "$have_gcc_asm_for_x64" = yes @@ -13573,12 +13574,13 @@ return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : have_gcc_asm_for_x87=yes else have_gcc_asm_for_x87=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x87" >&5 $as_echo "$have_gcc_asm_for_x87" >&6; } if test "$have_gcc_asm_for_x87" = yes @@ -13605,12 +13607,13 @@ return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : have_gcc_asm_for_mc68881=yes else have_gcc_asm_for_mc68881=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_mc68881" >&5 $as_echo "$have_gcc_asm_for_mc68881" >&6; } if test "$have_gcc_asm_for_mc68881" = yes diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -3910,7 +3910,7 @@ # ************************************** AC_MSG_CHECKING(for x64 gcc inline assembler) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ __asm__ __volatile__ ("movq %rcx, %rax"); ]])],[have_gcc_asm_for_x64=yes],[have_gcc_asm_for_x64=no]) AC_MSG_RESULT($have_gcc_asm_for_x64) @@ -4008,7 +4008,7 @@ # so we try it on all platforms. AC_MSG_CHECKING(whether we can use gcc inline assembler to get and set x87 control word) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ unsigned short cw; __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); @@ -4021,7 +4021,7 @@ fi AC_MSG_CHECKING(whether we can use gcc inline assembler to get and set mc68881 fpcr) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ unsigned int fpcr; __asm__ __volatile__ ("fmove.l %%fpcr,%0" : "=g" (fpcr)); __asm__ __volatile__ ("fmove.l %0,%%fpcr" : : "g" (fpcr)); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 20:31:03 2015 From: python-checkins at python.org (stefan.krah) Date: Thu, 02 Jul 2015 18:31:03 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NTQz?= =?utf-8?q?=3A_Use_AC=5FLINK_instead_of_AC=5FCOMPILE_in_order_to_prevent_f?= =?utf-8?q?alse?= Message-ID: <20150702183059.86858.44518@psf.io> https://hg.python.org/cpython/rev/2be983173f45 changeset: 96757:2be983173f45 branch: 3.5 parent: 96755:1692065524cc user: Stefan Krah date: Thu Jul 02 20:27:56 2015 +0200 summary: Issue #24543: Use AC_LINK instead of AC_COMPILE in order to prevent false positives with the -flto option (gcc >= 4.9.0 and clang). files: configure | 15 +++++++++------ configure.ac | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -13397,12 +13397,13 @@ return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : have_gcc_asm_for_x64=yes else have_gcc_asm_for_x64=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x64" >&5 $as_echo "$have_gcc_asm_for_x64" >&6; } if test "$have_gcc_asm_for_x64" = yes @@ -13573,12 +13574,13 @@ return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : have_gcc_asm_for_x87=yes else have_gcc_asm_for_x87=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x87" >&5 $as_echo "$have_gcc_asm_for_x87" >&6; } if test "$have_gcc_asm_for_x87" = yes @@ -13605,12 +13607,13 @@ return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : have_gcc_asm_for_mc68881=yes else have_gcc_asm_for_mc68881=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_mc68881" >&5 $as_echo "$have_gcc_asm_for_mc68881" >&6; } if test "$have_gcc_asm_for_mc68881" = yes diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -3910,7 +3910,7 @@ # ************************************** AC_MSG_CHECKING(for x64 gcc inline assembler) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ __asm__ __volatile__ ("movq %rcx, %rax"); ]])],[have_gcc_asm_for_x64=yes],[have_gcc_asm_for_x64=no]) AC_MSG_RESULT($have_gcc_asm_for_x64) @@ -4008,7 +4008,7 @@ # so we try it on all platforms. AC_MSG_CHECKING(whether we can use gcc inline assembler to get and set x87 control word) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ unsigned short cw; __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); @@ -4021,7 +4021,7 @@ fi AC_MSG_CHECKING(whether we can use gcc inline assembler to get and set mc68881 fpcr) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ unsigned int fpcr; __asm__ __volatile__ ("fmove.l %%fpcr,%0" : "=g" (fpcr)); __asm__ __volatile__ ("fmove.l %0,%%fpcr" : : "g" (fpcr)); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 23:19:40 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 02 Jul 2015 21:19:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_fix_use_after_?= =?utf-8?q?free_=28closes_=2324552=29?= Message-ID: <20150702211940.15337.9357@psf.io> https://hg.python.org/cpython/rev/24ce32d76376 changeset: 96759:24ce32d76376 branch: 3.4 parent: 96754:140b4b7b84bd user: Benjamin Peterson date: Thu Jul 02 16:18:38 2015 -0500 summary: fix use after free (closes #24552) files: Lib/test/pickletester.py | 12 ++++++++++++ Misc/NEWS | 2 ++ Modules/_pickle.c | 2 +- 3 files changed, 15 insertions(+), 1 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1039,6 +1039,18 @@ self.assertEqual(B(x), B(y), detail) self.assertEqual(x.__dict__, y.__dict__, detail) + def test_newobj_not_class(self): + # Issue 24552 + global SimpleNewObj + save = SimpleNewObj + o = object.__new__(SimpleNewObj) + b = self.dumps(o, 4) + try: + SimpleNewObj = 42 + self.assertRaises((TypeError, pickle.UnpicklingError), self.loads, b) + finally: + SimpleNewObj = save + # Register a type with copyreg, with extension code extcode. Pickle # an object of that type. Check that the resulting pickle uses opcode # (EXT[124]) under proto 2, and not in proto 1. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -64,6 +64,8 @@ Library ------- +- Issue #24552: Fix use after free in an error case of the _pickle module. + - Issue #24514: tarfile now tolerates number fields consisting of only whitespace. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -5210,10 +5210,10 @@ if (!PyType_Check(cls)) { Py_DECREF(kwargs); Py_DECREF(args); - Py_DECREF(cls); PyErr_Format(st->UnpicklingError, "NEWOBJ_EX class argument must be a type, not %.200s", Py_TYPE(cls)->tp_name); + Py_DECREF(cls); return -1; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 23:19:40 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 02 Jul 2015 21:19:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy41ICgjMjQ1NTIp?= Message-ID: <20150702211940.1304.55551@psf.io> https://hg.python.org/cpython/rev/32486bb59e7e changeset: 96761:32486bb59e7e parent: 96758:8f30776602b4 parent: 96760:24197b5f7126 user: Benjamin Peterson date: Thu Jul 02 16:19:05 2015 -0500 summary: merge 3.5 (#24552) files: Lib/test/pickletester.py | 12 ++++++++++++ Misc/NEWS | 2 ++ Modules/_pickle.c | 2 +- 3 files changed, 15 insertions(+), 1 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1039,6 +1039,18 @@ self.assertEqual(B(x), B(y), detail) self.assertEqual(x.__dict__, y.__dict__, detail) + def test_newobj_not_class(self): + # Issue 24552 + global SimpleNewObj + save = SimpleNewObj + o = object.__new__(SimpleNewObj) + b = self.dumps(o, 4) + try: + SimpleNewObj = 42 + self.assertRaises((TypeError, pickle.UnpicklingError), self.loads, b) + finally: + SimpleNewObj = save + # Register a type with copyreg, with extension code extcode. Pickle # an object of that type. Check that the resulting pickle uses opcode # (EXT[124]) under proto 2, and not in proto 1. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,8 @@ Library ------- +- Issue #24552: Fix use after free in an error case of the _pickle module. + - Issue #24514: tarfile now tolerates number fields consisting of only whitespace. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -5279,10 +5279,10 @@ if (!PyType_Check(cls)) { Py_DECREF(kwargs); Py_DECREF(args); - Py_DECREF(cls); PyErr_Format(st->UnpicklingError, "NEWOBJ_EX class argument must be a type, not %.200s", Py_TYPE(cls)->tp_name); + Py_DECREF(cls); return -1; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 23:19:42 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 02 Jul 2015 21:19:42 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_merge_3=2E4_=28=2324552=29?= Message-ID: <20150702211940.27321.77170@psf.io> https://hg.python.org/cpython/rev/24197b5f7126 changeset: 96760:24197b5f7126 branch: 3.5 parent: 96757:2be983173f45 parent: 96759:24ce32d76376 user: Benjamin Peterson date: Thu Jul 02 16:18:58 2015 -0500 summary: merge 3.4 (#24552) files: Lib/test/pickletester.py | 12 ++++++++++++ Misc/NEWS | 2 ++ Modules/_pickle.c | 2 +- 3 files changed, 15 insertions(+), 1 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1039,6 +1039,18 @@ self.assertEqual(B(x), B(y), detail) self.assertEqual(x.__dict__, y.__dict__, detail) + def test_newobj_not_class(self): + # Issue 24552 + global SimpleNewObj + save = SimpleNewObj + o = object.__new__(SimpleNewObj) + b = self.dumps(o, 4) + try: + SimpleNewObj = 42 + self.assertRaises((TypeError, pickle.UnpicklingError), self.loads, b) + finally: + SimpleNewObj = save + # Register a type with copyreg, with extension code extcode. Pickle # an object of that type. Check that the resulting pickle uses opcode # (EXT[124]) under proto 2, and not in proto 1. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,8 @@ Library ------- +- Issue #24552: Fix use after free in an error case of the _pickle module. + - Issue #24514: tarfile now tolerates number fields consisting of only whitespace. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -5279,10 +5279,10 @@ if (!PyType_Check(cls)) { Py_DECREF(kwargs); Py_DECREF(args); - Py_DECREF(cls); PyErr_Format(st->UnpicklingError, "NEWOBJ_EX class argument must be a type, not %.200s", Py_TYPE(cls)->tp_name); + Py_DECREF(cls); return -1; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 23:59:17 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 02 Jul 2015 21:59:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_use_correct_?= =?utf-8?b?X19uZXdfXyBtZXRob2QgKGNsb3NlcyAjMjQ1NTIp?= Message-ID: <20150702215916.66728.17581@psf.io> https://hg.python.org/cpython/rev/978bc1ff43a7 changeset: 96762:978bc1ff43a7 branch: 3.4 parent: 96759:24ce32d76376 user: Benjamin Peterson date: Thu Jul 02 16:58:22 2015 -0500 summary: use correct __new__ method (closes #24552) files: Lib/test/pickletester.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1043,7 +1043,7 @@ # Issue 24552 global SimpleNewObj save = SimpleNewObj - o = object.__new__(SimpleNewObj) + o = SimpleNewObj.__new__(SimpleNewObj) b = self.dumps(o, 4) try: SimpleNewObj = 42 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 23:59:17 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 02 Jul 2015 21:59:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy41?= Message-ID: <20150702215917.111341.81089@psf.io> https://hg.python.org/cpython/rev/14be2ab42294 changeset: 96764:14be2ab42294 parent: 96761:32486bb59e7e parent: 96763:b1caa38c81ab user: Benjamin Peterson date: Thu Jul 02 16:58:38 2015 -0500 summary: merge 3.5 files: Lib/test/pickletester.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1043,7 +1043,7 @@ # Issue 24552 global SimpleNewObj save = SimpleNewObj - o = object.__new__(SimpleNewObj) + o = SimpleNewObj.__new__(SimpleNewObj) b = self.dumps(o, 4) try: SimpleNewObj = 42 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 2 23:59:17 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 02 Jul 2015 21:59:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_merge_3=2E4?= Message-ID: <20150702215916.32358.65377@psf.io> https://hg.python.org/cpython/rev/b1caa38c81ab changeset: 96763:b1caa38c81ab branch: 3.5 parent: 96760:24197b5f7126 parent: 96762:978bc1ff43a7 user: Benjamin Peterson date: Thu Jul 02 16:58:31 2015 -0500 summary: merge 3.4 files: Lib/test/pickletester.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1043,7 +1043,7 @@ # Issue 24552 global SimpleNewObj save = SimpleNewObj - o = object.__new__(SimpleNewObj) + o = SimpleNewObj.__new__(SimpleNewObj) b = self.dumps(o, 4) try: SimpleNewObj = 42 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 06:24:23 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 04:24:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChJc3N1ZSAjMjQ0NTAp?= Message-ID: <20150703042423.32451.10257@psf.io> https://hg.python.org/cpython/rev/f4058528ab8c changeset: 96766:f4058528ab8c parent: 96764:14be2ab42294 parent: 96765:84eb9a020011 user: Yury Selivanov date: Fri Jul 03 00:24:14 2015 -0400 summary: Merge 3.5 (Issue #24450) files: Doc/library/inspect.rst | 7 ++++ Doc/whatsnew/3.5.rst | 3 ++ Lib/test/test_coroutines.py | 30 ++++++++++++++++++++ Lib/test/test_generators.py | 37 ++++++++++++++++++++++++- Misc/NEWS | 3 ++ Objects/genobject.c | 22 ++++++++++++++ 6 files changed, 101 insertions(+), 1 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -182,12 +182,19 @@ +-----------+-----------------+---------------------------+ | | __qualname__ | qualified name | +-----------+-----------------+---------------------------+ +| | cr_await | object being awaited on, | +| | | or ``None`` | ++-----------+-----------------+---------------------------+ | | cr_frame | frame | +-----------+-----------------+---------------------------+ | | cr_running | is the coroutine running? | +-----------+-----------------+---------------------------+ | | cr_code | code | +-----------+-----------------+---------------------------+ +| | gi_yieldfrom | object being iterated by | +| | | ``yield from``, or | +| | | ``None`` | ++-----------+-----------------+---------------------------+ | builtin | __doc__ | documentation string | +-----------+-----------------+---------------------------+ | | __name__ | original name of this | diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -84,6 +84,9 @@ * ``b'\xf0\x9f\x90\x8d'.hex()``, ``bytearray(b'\xf0\x9f\x90\x8d').hex()``, ``memoryview(b'\xf0\x9f\x90\x8d').hex()``: :issue:`9951` - A ``hex`` method has been added to bytes, bytearray, and memoryview. +* Generators have new ``gi_yieldfrom`` attribute, which returns the + object being iterated by ``yield from`` expressions. (Contributed + by Benno Leslie and Yury Selivanov in :issue:`24450`.) Implementation improvements: diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -350,6 +350,36 @@ "coroutine ignored GeneratorExit"): c.close() + def test_cr_await(self): + @types.coroutine + def a(): + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_RUNNING) + self.assertIsNone(coro_b.cr_await) + yield + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_RUNNING) + self.assertIsNone(coro_b.cr_await) + + async def c(): + await a() + + async def b(): + self.assertIsNone(coro_b.cr_await) + await c() + self.assertIsNone(coro_b.cr_await) + + coro_b = b() + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_CREATED) + self.assertIsNone(coro_b.cr_await) + + coro_b.send(None) + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_SUSPENDED) + self.assertEqual(coro_b.cr_await.cr_await.gi_code.co_name, 'a') + + with self.assertRaises(StopIteration): + coro_b.send(None) # complete coroutine + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_CLOSED) + self.assertIsNone(coro_b.cr_await) + def test_corotype_1(self): ct = types.CoroutineType self.assertIn('into coroutine', ct.send.__doc__) 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 @@ -3,6 +3,8 @@ import unittest import warnings import weakref +import inspect +import types from test import support @@ -259,6 +261,39 @@ next(g) +class YieldFromTests(unittest.TestCase): + def test_generator_gi_yieldfrom(self): + def a(): + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_RUNNING) + self.assertIsNone(gen_b.gi_yieldfrom) + yield + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_RUNNING) + self.assertIsNone(gen_b.gi_yieldfrom) + + def b(): + self.assertIsNone(gen_b.gi_yieldfrom) + yield from a() + self.assertIsNone(gen_b.gi_yieldfrom) + yield + self.assertIsNone(gen_b.gi_yieldfrom) + + gen_b = b() + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_CREATED) + self.assertIsNone(gen_b.gi_yieldfrom) + + gen_b.send(None) + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_SUSPENDED) + self.assertEqual(gen_b.gi_yieldfrom.gi_code.co_name, 'a') + + gen_b.send(None) + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_SUSPENDED) + self.assertIsNone(gen_b.gi_yieldfrom) + + [] = gen_b # Exhaust generator + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_CLOSED) + self.assertIsNone(gen_b.gi_yieldfrom) + + tutorial_tests = """ Let's try a simple generator: @@ -624,7 +659,7 @@ >>> type(i) >>> [s for s in dir(i) if not s.startswith('_')] -['close', 'gi_code', 'gi_frame', 'gi_running', 'send', 'throw'] +['close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw'] >>> from test.support import HAVE_DOCSTRINGS >>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).') Implement next(self). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,9 @@ used in types.coroutine to be instance of collections.abc.Generator; inspect.isawaitable was removed (use collections.abc.Awaitable). +- Issue #24450: Add gi_yieldfrom to generators and cr_await to coroutines. + Contributed by Benno Leslie and Yury Selivanov. + Library ------- diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -552,11 +552,22 @@ return 0; } +static PyObject * +gen_getyieldfrom(PyGenObject *gen) +{ + PyObject *yf = gen_yf(gen); + if (yf == NULL) + Py_RETURN_NONE; + return yf; +} + static PyGetSetDef gen_getsetlist[] = { {"__name__", (getter)gen_get_name, (setter)gen_set_name, PyDoc_STR("name of the generator")}, {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, PyDoc_STR("qualified name of the generator")}, + {"gi_yieldfrom", (getter)gen_getyieldfrom, NULL, + PyDoc_STR("object being iterated by yield from, or None")}, {NULL} /* Sentinel */ }; @@ -776,11 +787,22 @@ return (PyObject *)cw; } +static PyObject * +coro_get_cr_await(PyCoroObject *coro) +{ + PyObject *yf = gen_yf((PyGenObject *) coro); + if (yf == NULL) + Py_RETURN_NONE; + return yf; +} + static PyGetSetDef coro_getsetlist[] = { {"__name__", (getter)gen_get_name, (setter)gen_set_name, PyDoc_STR("name of the coroutine")}, {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, PyDoc_STR("qualified name of the coroutine")}, + {"cr_await", (getter)coro_get_cr_await, NULL, + PyDoc_STR("object being awaited on, or None")}, {NULL} /* Sentinel */ }; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 06:24:23 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 04:24:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NDUw?= =?utf-8?q?=3A_Add_gi=5Fyieldfrom_to_generators=3B_cr=5Fawait_to_coroutine?= =?utf-8?q?s=2E?= Message-ID: <20150703042423.106268.39153@psf.io> https://hg.python.org/cpython/rev/84eb9a020011 changeset: 96765:84eb9a020011 branch: 3.5 parent: 96763:b1caa38c81ab user: Yury Selivanov date: Fri Jul 03 00:23:30 2015 -0400 summary: Issue #24450: Add gi_yieldfrom to generators; cr_await to coroutines. Patch by Benno Leslie and Yury Selivanov. files: Doc/library/inspect.rst | 7 ++++ Doc/whatsnew/3.5.rst | 3 ++ Lib/test/test_coroutines.py | 30 ++++++++++++++++++++ Lib/test/test_generators.py | 37 ++++++++++++++++++++++++- Misc/NEWS | 3 ++ Objects/genobject.c | 22 ++++++++++++++ 6 files changed, 101 insertions(+), 1 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -182,12 +182,19 @@ +-----------+-----------------+---------------------------+ | | __qualname__ | qualified name | +-----------+-----------------+---------------------------+ +| | cr_await | object being awaited on, | +| | | or ``None`` | ++-----------+-----------------+---------------------------+ | | cr_frame | frame | +-----------+-----------------+---------------------------+ | | cr_running | is the coroutine running? | +-----------+-----------------+---------------------------+ | | cr_code | code | +-----------+-----------------+---------------------------+ +| | gi_yieldfrom | object being iterated by | +| | | ``yield from``, or | +| | | ``None`` | ++-----------+-----------------+---------------------------+ | builtin | __doc__ | documentation string | +-----------+-----------------+---------------------------+ | | __name__ | original name of this | diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -84,6 +84,9 @@ * ``b'\xf0\x9f\x90\x8d'.hex()``, ``bytearray(b'\xf0\x9f\x90\x8d').hex()``, ``memoryview(b'\xf0\x9f\x90\x8d').hex()``: :issue:`9951` - A ``hex`` method has been added to bytes, bytearray, and memoryview. +* Generators have new ``gi_yieldfrom`` attribute, which returns the + object being iterated by ``yield from`` expressions. (Contributed + by Benno Leslie and Yury Selivanov in :issue:`24450`.) Implementation improvements: diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -350,6 +350,36 @@ "coroutine ignored GeneratorExit"): c.close() + def test_cr_await(self): + @types.coroutine + def a(): + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_RUNNING) + self.assertIsNone(coro_b.cr_await) + yield + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_RUNNING) + self.assertIsNone(coro_b.cr_await) + + async def c(): + await a() + + async def b(): + self.assertIsNone(coro_b.cr_await) + await c() + self.assertIsNone(coro_b.cr_await) + + coro_b = b() + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_CREATED) + self.assertIsNone(coro_b.cr_await) + + coro_b.send(None) + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_SUSPENDED) + self.assertEqual(coro_b.cr_await.cr_await.gi_code.co_name, 'a') + + with self.assertRaises(StopIteration): + coro_b.send(None) # complete coroutine + self.assertEqual(inspect.getcoroutinestate(coro_b), inspect.CORO_CLOSED) + self.assertIsNone(coro_b.cr_await) + def test_corotype_1(self): ct = types.CoroutineType self.assertIn('into coroutine', ct.send.__doc__) 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 @@ -3,6 +3,8 @@ import unittest import warnings import weakref +import inspect +import types from test import support @@ -259,6 +261,39 @@ next(g) +class YieldFromTests(unittest.TestCase): + def test_generator_gi_yieldfrom(self): + def a(): + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_RUNNING) + self.assertIsNone(gen_b.gi_yieldfrom) + yield + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_RUNNING) + self.assertIsNone(gen_b.gi_yieldfrom) + + def b(): + self.assertIsNone(gen_b.gi_yieldfrom) + yield from a() + self.assertIsNone(gen_b.gi_yieldfrom) + yield + self.assertIsNone(gen_b.gi_yieldfrom) + + gen_b = b() + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_CREATED) + self.assertIsNone(gen_b.gi_yieldfrom) + + gen_b.send(None) + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_SUSPENDED) + self.assertEqual(gen_b.gi_yieldfrom.gi_code.co_name, 'a') + + gen_b.send(None) + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_SUSPENDED) + self.assertIsNone(gen_b.gi_yieldfrom) + + [] = gen_b # Exhaust generator + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_CLOSED) + self.assertIsNone(gen_b.gi_yieldfrom) + + tutorial_tests = """ Let's try a simple generator: @@ -624,7 +659,7 @@ >>> type(i) >>> [s for s in dir(i) if not s.startswith('_')] -['close', 'gi_code', 'gi_frame', 'gi_running', 'send', 'throw'] +['close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw'] >>> from test.support import HAVE_DOCSTRINGS >>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).') Implement next(self). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ used in types.coroutine to be instance of collections.abc.Generator; inspect.isawaitable was removed (use collections.abc.Awaitable). +- Issue #24450: Add gi_yieldfrom to generators and cr_await to coroutines. + Contributed by Benno Leslie and Yury Selivanov. + Library ------- diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -552,11 +552,22 @@ return 0; } +static PyObject * +gen_getyieldfrom(PyGenObject *gen) +{ + PyObject *yf = gen_yf(gen); + if (yf == NULL) + Py_RETURN_NONE; + return yf; +} + static PyGetSetDef gen_getsetlist[] = { {"__name__", (getter)gen_get_name, (setter)gen_set_name, PyDoc_STR("name of the generator")}, {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, PyDoc_STR("qualified name of the generator")}, + {"gi_yieldfrom", (getter)gen_getyieldfrom, NULL, + PyDoc_STR("object being iterated by yield from, or None")}, {NULL} /* Sentinel */ }; @@ -776,11 +787,22 @@ return (PyObject *)cw; } +static PyObject * +coro_get_cr_await(PyCoroObject *coro) +{ + PyObject *yf = gen_yf((PyGenObject *) coro); + if (yf == NULL) + Py_RETURN_NONE; + return yf; +} + static PyGetSetDef coro_getsetlist[] = { {"__name__", (getter)gen_get_name, (setter)gen_set_name, PyDoc_STR("name of the coroutine")}, {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, PyDoc_STR("qualified name of the coroutine")}, + {"cr_await", (getter)coro_get_cr_await, NULL, + PyDoc_STR("object being awaited on, or None")}, {NULL} /* Sentinel */ }; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 06:35:46 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 04:35:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NDUw?= =?utf-8?q?=3A_Proxy_cr=5Fawait_and_gi=5Fyieldfrom_in_=40types=2Ecoroutine?= Message-ID: <20150703043546.3167.59526@psf.io> https://hg.python.org/cpython/rev/9bae275e99b3 changeset: 96767:9bae275e99b3 branch: 3.5 parent: 96765:84eb9a020011 user: Yury Selivanov date: Fri Jul 03 00:35:02 2015 -0400 summary: Issue #24450: Proxy cr_await and gi_yieldfrom in @types.coroutine files: Lib/test/test_types.py | 7 +++++-- Lib/types.py | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -1295,8 +1295,8 @@ self.assertIs(wrapper.__name__, gen.__name__) # Test AttributeErrors - for name in {'gi_running', 'gi_frame', 'gi_code', - 'cr_running', 'cr_frame', 'cr_code'}: + for name in {'gi_running', 'gi_frame', 'gi_code', 'gi_yieldfrom', + 'cr_running', 'cr_frame', 'cr_code', 'cr_await'}: with self.assertRaises(AttributeError): getattr(wrapper, name) @@ -1304,12 +1304,15 @@ gen.gi_running = object() gen.gi_frame = object() gen.gi_code = object() + gen.gi_yieldfrom = object() self.assertIs(wrapper.gi_running, gen.gi_running) self.assertIs(wrapper.gi_frame, gen.gi_frame) self.assertIs(wrapper.gi_code, gen.gi_code) + self.assertIs(wrapper.gi_yieldfrom, gen.gi_yieldfrom) self.assertIs(wrapper.cr_running, gen.gi_running) self.assertIs(wrapper.cr_frame, gen.gi_frame) self.assertIs(wrapper.cr_code, gen.gi_code) + self.assertIs(wrapper.cr_await, gen.gi_yieldfrom) wrapper.close() gen.close.assert_called_once_with() diff --git a/Lib/types.py b/Lib/types.py --- a/Lib/types.py +++ b/Lib/types.py @@ -188,9 +188,13 @@ @property def gi_running(self): return self.__wrapped.gi_running + @property + def gi_yieldfrom(self): + return self.__wrapped.gi_yieldfrom cr_code = gi_code cr_frame = gi_frame cr_running = gi_running + cr_await = gi_yieldfrom def __next__(self): return next(self.__wrapped) def __iter__(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 06:35:46 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 04:35:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChJc3N1ZSAjMjQ0NTAp?= Message-ID: <20150703043546.29010.89839@psf.io> https://hg.python.org/cpython/rev/4d3bd9b82a62 changeset: 96768:4d3bd9b82a62 parent: 96766:f4058528ab8c parent: 96767:9bae275e99b3 user: Yury Selivanov date: Fri Jul 03 00:35:29 2015 -0400 summary: Merge 3.5 (Issue #24450) files: Lib/test/test_types.py | 7 +++++-- Lib/types.py | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -1295,8 +1295,8 @@ self.assertIs(wrapper.__name__, gen.__name__) # Test AttributeErrors - for name in {'gi_running', 'gi_frame', 'gi_code', - 'cr_running', 'cr_frame', 'cr_code'}: + for name in {'gi_running', 'gi_frame', 'gi_code', 'gi_yieldfrom', + 'cr_running', 'cr_frame', 'cr_code', 'cr_await'}: with self.assertRaises(AttributeError): getattr(wrapper, name) @@ -1304,12 +1304,15 @@ gen.gi_running = object() gen.gi_frame = object() gen.gi_code = object() + gen.gi_yieldfrom = object() self.assertIs(wrapper.gi_running, gen.gi_running) self.assertIs(wrapper.gi_frame, gen.gi_frame) self.assertIs(wrapper.gi_code, gen.gi_code) + self.assertIs(wrapper.gi_yieldfrom, gen.gi_yieldfrom) self.assertIs(wrapper.cr_running, gen.gi_running) self.assertIs(wrapper.cr_frame, gen.gi_frame) self.assertIs(wrapper.cr_code, gen.gi_code) + self.assertIs(wrapper.cr_await, gen.gi_yieldfrom) wrapper.close() gen.close.assert_called_once_with() diff --git a/Lib/types.py b/Lib/types.py --- a/Lib/types.py +++ b/Lib/types.py @@ -188,9 +188,13 @@ @property def gi_running(self): return self.__wrapped.gi_running + @property + def gi_yieldfrom(self): + return self.__wrapped.gi_yieldfrom cr_code = gi_code cr_frame = gi_frame cr_running = gi_running + cr_await = gi_yieldfrom def __next__(self): return next(self.__wrapped) def __iter__(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 06:42:13 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 04:42:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI0NDUw?= =?utf-8?q?=3A_Proxy_gi=5Fyieldfrom_=26_cr=5Fawait_in_asyncio=2ECoroWrappe?= =?utf-8?q?r?= Message-ID: <20150703044213.89409.96125@psf.io> https://hg.python.org/cpython/rev/34460219c0e0 changeset: 96769:34460219c0e0 branch: 3.4 parent: 96762:978bc1ff43a7 user: Yury Selivanov date: Fri Jul 03 00:41:16 2015 -0400 summary: Issue #24450: Proxy gi_yieldfrom & cr_await in asyncio.CoroWrapper files: Lib/asyncio/coroutines.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -145,6 +145,14 @@ __await__ = __iter__ # make compatible with 'await' expression @property + def gi_yieldfrom(self): + return self.gen.gi_yieldfrom + + @property + def cr_await(self): + return self.gen.cr_await + + @property def cr_running(self): return self.gen.cr_running -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 06:42:13 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 04:42:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChJc3N1ZSAjMjQ0NTAp?= Message-ID: <20150703044213.6456.79456@psf.io> https://hg.python.org/cpython/rev/5e9f794fd776 changeset: 96771:5e9f794fd776 parent: 96768:4d3bd9b82a62 parent: 96770:3555f7b5eac6 user: Yury Selivanov date: Fri Jul 03 00:42:01 2015 -0400 summary: Merge 3.5 (Issue #24450) files: Lib/asyncio/coroutines.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -145,6 +145,14 @@ __await__ = __iter__ # make compatible with 'await' expression @property + def gi_yieldfrom(self): + return self.gen.gi_yieldfrom + + @property + def cr_await(self): + return self.gen.cr_await + + @property def cr_running(self): return self.gen.cr_running -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 06:42:13 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 04:42:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Merge_3=2E4_=28Issue_=2324450=29?= Message-ID: <20150703044213.23315.50701@psf.io> https://hg.python.org/cpython/rev/3555f7b5eac6 changeset: 96770:3555f7b5eac6 branch: 3.5 parent: 96767:9bae275e99b3 parent: 96769:34460219c0e0 user: Yury Selivanov date: Fri Jul 03 00:41:40 2015 -0400 summary: Merge 3.4 (Issue #24450) files: Lib/asyncio/coroutines.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -145,6 +145,14 @@ __await__ = __iter__ # make compatible with 'await' expression @property + def gi_yieldfrom(self): + return self.gen.gi_yieldfrom + + @property + def cr_await(self): + return self.gen.cr_await + + @property def cr_running(self): return self.gen.cr_running -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 07:12:42 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 05:12:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChJc3N1ZSAjMTkyMzUp?= Message-ID: <20150703051241.108523.84358@psf.io> https://hg.python.org/cpython/rev/749d74e5dfa7 changeset: 96773:749d74e5dfa7 parent: 96771:5e9f794fd776 parent: 96772:a795cf73ce6f user: Yury Selivanov date: Fri Jul 03 01:10:11 2015 -0400 summary: Merge 3.5 (Issue #19235) files: Doc/c-api/exceptions.rst | 12 ++++++-- Doc/library/exceptions.rst | 10 ++++++ Doc/library/pickle.rst | 2 +- Doc/whatsnew/3.5.rst | 2 + Include/ceval.h | 6 ++-- Include/pyerrors.h | 1 + Lib/ctypes/test/test_as_parameter.py | 2 +- Lib/test/exception_hierarchy.txt | 1 + Lib/test/list_tests.py | 2 +- Lib/test/test_class.py | 4 +- Lib/test/test_compile.py | 2 +- Lib/test/test_copy.py | 6 ++-- Lib/test/test_descr.py | 6 ++-- Lib/test/test_dictviews.py | 2 +- Lib/test/test_exceptions.py | 13 ++++---- Lib/test/test_isinstance.py | 10 +++--- Lib/test/test_json/test_recursion.py | 12 ++++---- Lib/test/test_pickle.py | 3 +- Lib/test/test_richcmp.py | 24 ++++++++-------- Lib/test/test_runpy.py | 2 +- Lib/test/test_sys.py | 6 ++-- Lib/test/test_threading.py | 2 +- Misc/NEWS | 2 + Modules/_pickle.c | 2 +- Modules/_sre.c | 3 +- Objects/exceptions.c | 19 ++++++++---- Objects/typeobject.c | 2 +- Python/ceval.c | 2 +- Python/errors.c | 2 +- Python/symtable.c | 4 +- Tools/scripts/find_recursionlimit.py | 4 +- 31 files changed, 101 insertions(+), 69 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 @@ -683,12 +683,12 @@ sets a :exc:`MemoryError` and returns a nonzero value. The function then checks if the recursion limit is reached. If this is the - case, a :exc:`RuntimeError` is set and a nonzero value is returned. + case, a :exc:`RecursionError` is set and a nonzero value is returned. Otherwise, zero is returned. *where* should be a string such as ``" in instance check"`` to be - concatenated to the :exc:`RuntimeError` message caused by the recursion depth - limit. + concatenated to the :exc:`RecursionError` message caused by the recursion + depth limit. .. c:function:: void Py_LeaveRecursiveCall() @@ -800,6 +800,8 @@ +-----------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_ProcessLookupError` | :exc:`ProcessLookupError` | | +-----------------------------------------+---------------------------------+----------+ +| :c:data:`PyExc_RecursionError` | :exc:`RecursionError` | | ++-----------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_ReferenceError` | :exc:`ReferenceError` | \(2) | +-----------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_RuntimeError` | :exc:`RuntimeError` | | @@ -829,6 +831,9 @@ :c:data:`PyExc_PermissionError`, :c:data:`PyExc_ProcessLookupError` and :c:data:`PyExc_TimeoutError` were introduced following :pep:`3151`. +.. versionadded:: 3.5 + :c:data:`PyExc_RecursionError`. + These are compatibility aliases to :c:data:`PyExc_OSError`: @@ -877,6 +882,7 @@ single: PyExc_OverflowError single: PyExc_PermissionError single: PyExc_ProcessLookupError + single: PyExc_RecursionError single: PyExc_ReferenceError single: PyExc_RuntimeError single: PyExc_SyntaxError diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -282,6 +282,16 @@ handling in C, most floating point operations are not checked. +.. exception:: RecursionError + + This exception is derived from :exc:`RuntimeError`. It is raised when the + interpreter detects that the maximum recursion depth (see + :func:`sys.getrecursionlimit`) is exceeded. + + .. versionadded:: 3.5 + Previously, a plain :exc:`RuntimeError` was raised. + + .. exception:: ReferenceError This exception is raised when a weak reference proxy, created by the diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -425,7 +425,7 @@ Attempts to pickle unpicklable objects will raise the :exc:`PicklingError` exception; when this happens, an unspecified number of bytes may have already been written to the underlying file. Trying to pickle a highly recursive data -structure may exceed the maximum recursion depth, a :exc:`RuntimeError` will be +structure may exceed the maximum recursion depth, a :exc:`RecursionError` will be raised in this case. You can carefully raise this limit with :func:`sys.setrecursionlimit`. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -87,6 +87,8 @@ * Generators have new ``gi_yieldfrom`` attribute, which returns the object being iterated by ``yield from`` expressions. (Contributed by Benno Leslie and Yury Selivanov in :issue:`24450`.) +* New :exc:`RecursionError` exception. (Contributed by Georg Brandl + in :issue:`19235`.) Implementation improvements: diff --git a/Include/ceval.h b/Include/ceval.h --- a/Include/ceval.h +++ b/Include/ceval.h @@ -48,16 +48,16 @@ In Python 3.0, this protection has two levels: * normal anti-recursion protection is triggered when the recursion level - exceeds the current recursion limit. It raises a RuntimeError, and sets + exceeds the current recursion limit. It raises a RecursionError, and sets the "overflowed" flag in the thread state structure. This flag temporarily *disables* the normal protection; this allows cleanup code to potentially outgrow the recursion limit while processing the - RuntimeError. + RecursionError. * "last chance" anti-recursion protection is triggered when the recursion level exceeds "current recursion limit + 50". By construction, this protection can only be triggered when the "overflowed" flag is set. It means the cleanup code has itself gone into an infinite loop, or the - RuntimeError has been mistakingly ignored. When this protection is + RecursionError has been mistakingly ignored. When this protection is triggered, the interpreter aborts with a Fatal Error. In addition, the "overflowed" flag is automatically reset when the diff --git a/Include/pyerrors.h b/Include/pyerrors.h --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -167,6 +167,7 @@ PyAPI_DATA(PyObject *) PyExc_NameError; PyAPI_DATA(PyObject *) PyExc_OverflowError; PyAPI_DATA(PyObject *) PyExc_RuntimeError; +PyAPI_DATA(PyObject *) PyExc_RecursionError; PyAPI_DATA(PyObject *) PyExc_NotImplementedError; PyAPI_DATA(PyObject *) PyExc_SyntaxError; PyAPI_DATA(PyObject *) PyExc_IndentationError; diff --git a/Lib/ctypes/test/test_as_parameter.py b/Lib/ctypes/test/test_as_parameter.py --- a/Lib/ctypes/test/test_as_parameter.py +++ b/Lib/ctypes/test/test_as_parameter.py @@ -194,7 +194,7 @@ a = A() a._as_parameter_ = a - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): c_int.from_param(a) 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 @@ -39,6 +39,7 @@ +-- ReferenceError +-- RuntimeError | +-- NotImplementedError + | +-- RecursionError +-- SyntaxError | +-- IndentationError | +-- TabError diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py --- a/Lib/test/list_tests.py +++ b/Lib/test/list_tests.py @@ -56,7 +56,7 @@ l0 = [] for i in range(sys.getrecursionlimit() + 100): l0 = [l0] - self.assertRaises(RuntimeError, repr, l0) + self.assertRaises(RecursionError, repr, l0) def test_print(self): d = self.type2test(range(200)) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -500,10 +500,10 @@ try: a() # This should not segfault - except RuntimeError: + except RecursionError: pass else: - self.fail("Failed to raise RuntimeError") + self.fail("Failed to raise RecursionError") def testForExceptionsRaisedInInstanceGetattr2(self): # Tests for exceptions raised in instance_getattr2(). diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -534,7 +534,7 @@ broken = prefix + repeated * fail_depth details = "Compiling ({!r} + {!r} * {})".format( prefix, repeated, fail_depth) - with self.assertRaises(RuntimeError, msg=details): + with self.assertRaises(RecursionError, msg=details): self.compile_single(broken) check_limit("a", "()") diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py --- a/Lib/test/test_copy.py +++ b/Lib/test/test_copy.py @@ -327,7 +327,7 @@ x.append(x) y = copy.deepcopy(x) for op in comparisons: - self.assertRaises(RuntimeError, op, y, x) + self.assertRaises(RecursionError, op, y, x) self.assertIsNot(y, x) self.assertIs(y[0], y) self.assertEqual(len(y), 1) @@ -354,7 +354,7 @@ x[0].append(x) y = copy.deepcopy(x) for op in comparisons: - self.assertRaises(RuntimeError, op, y, x) + self.assertRaises(RecursionError, op, y, x) self.assertIsNot(y, x) self.assertIsNot(y[0], x[0]) self.assertIs(y[0][0], y) @@ -373,7 +373,7 @@ for op in order_comparisons: self.assertRaises(TypeError, op, y, x) for op in equality_comparisons: - self.assertRaises(RuntimeError, op, y, x) + self.assertRaises(RecursionError, op, y, x) self.assertIsNot(y, x) self.assertIs(y['foo'], y) self.assertEqual(len(y), 1) 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 @@ -3342,7 +3342,7 @@ A.__call__ = A() try: A()() - except RuntimeError: + except RecursionError: pass else: self.fail("Recursion limit should have been reached for __call__()") @@ -4317,8 +4317,8 @@ pass Foo.__repr__ = Foo.__str__ foo = Foo() - self.assertRaises(RuntimeError, str, foo) - self.assertRaises(RuntimeError, repr, foo) + self.assertRaises(RecursionError, str, foo) + self.assertRaises(RecursionError, repr, foo) def test_mixing_slot_wrappers(self): class X(dict): diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py --- a/Lib/test/test_dictviews.py +++ b/Lib/test/test_dictviews.py @@ -196,7 +196,7 @@ def test_recursive_repr(self): d = {} d[42] = d.values() - self.assertRaises(RuntimeError, repr, d) + self.assertRaises(RecursionError, repr, d) def test_abc_registry(self): d = dict(a=1) 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 @@ -84,6 +84,7 @@ x += x # this simply shouldn't blow up self.raise_catch(RuntimeError, "RuntimeError") + self.raise_catch(RecursionError, "RecursionError") self.raise_catch(SyntaxError, "SyntaxError") try: exec('/\n') @@ -474,14 +475,14 @@ def testInfiniteRecursion(self): def f(): return f() - self.assertRaises(RuntimeError, f) + self.assertRaises(RecursionError, f) def g(): try: return g() except ValueError: return -1 - self.assertRaises(RuntimeError, g) + self.assertRaises(RecursionError, g) def test_str(self): # Make sure both instances and classes have a str representation. @@ -887,10 +888,10 @@ def g(): try: return g() - except RuntimeError: + except RecursionError: return sys.exc_info() e, v, tb = g() - self.assertTrue(isinstance(v, RuntimeError), type(v)) + self.assertTrue(isinstance(v, RecursionError), type(v)) self.assertIn("maximum recursion depth exceeded", str(v)) @@ -989,10 +990,10 @@ # We cannot use assertRaises since it manually deletes the traceback try: inner() - except RuntimeError as e: + except RecursionError as e: self.assertNotEqual(wr(), None) else: - self.fail("RuntimeError not raised") + self.fail("RecursionError not raised") self.assertEqual(wr(), None) def test_errno_ENOTDIR(self): diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py --- a/Lib/test/test_isinstance.py +++ b/Lib/test/test_isinstance.py @@ -258,18 +258,18 @@ self.assertEqual(True, issubclass(str, (str, (Child, NewChild, str)))) def test_subclass_recursion_limit(self): - # make sure that issubclass raises RuntimeError before the C stack is + # make sure that issubclass raises RecursionError before the C stack is # blown - self.assertRaises(RuntimeError, blowstack, issubclass, str, str) + self.assertRaises(RecursionError, blowstack, issubclass, str, str) def test_isinstance_recursion_limit(self): - # make sure that issubclass raises RuntimeError before the C stack is + # make sure that issubclass raises RecursionError before the C stack is # blown - self.assertRaises(RuntimeError, blowstack, isinstance, '', str) + self.assertRaises(RecursionError, blowstack, isinstance, '', str) def blowstack(fxn, arg, compare_to): # Make sure that calling isinstance with a deeply nested tuple for its - # argument will raise RuntimeError eventually. + # argument will raise RecursionError eventually. tuple_arg = (compare_to,) for cnt in range(sys.getrecursionlimit()+5): tuple_arg = (tuple_arg,) diff --git a/Lib/test/test_json/test_recursion.py b/Lib/test/test_json/test_recursion.py --- a/Lib/test/test_json/test_recursion.py +++ b/Lib/test/test_json/test_recursion.py @@ -68,11 +68,11 @@ def test_highly_nested_objects_decoding(self): # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.loads('{"a":' * 100000 + '1' + '}' * 100000) - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.loads('{"a":' * 100000 + '[1]' + '}' * 100000) - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.loads('[' * 100000 + '1' + ']' * 100000) def test_highly_nested_objects_encoding(self): @@ -80,9 +80,9 @@ l, d = [], {} for x in range(100000): l, d = [l], {'k':d} - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.dumps(l) - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.dumps(d) def test_endless_recursion(self): @@ -92,7 +92,7 @@ """If check_circular is False, this will keep adding another list.""" return [o] - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): EndlessJSONEncoder(check_circular=False).encode(5j) 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 @@ -353,7 +353,8 @@ with self.subTest(name): if exc in (BlockingIOError, ResourceWarning, - StopAsyncIteration): + StopAsyncIteration, + RecursionError): continue if exc is not OSError and issubclass(exc, OSError): self.assertEqual(reverse_mapping('builtins', name), diff --git a/Lib/test/test_richcmp.py b/Lib/test/test_richcmp.py --- a/Lib/test/test_richcmp.py +++ b/Lib/test/test_richcmp.py @@ -228,25 +228,25 @@ b = UserList() a.append(b) b.append(a) - self.assertRaises(RuntimeError, operator.eq, a, b) - self.assertRaises(RuntimeError, operator.ne, a, b) - self.assertRaises(RuntimeError, operator.lt, a, b) - self.assertRaises(RuntimeError, operator.le, a, b) - self.assertRaises(RuntimeError, operator.gt, a, b) - self.assertRaises(RuntimeError, operator.ge, a, b) + self.assertRaises(RecursionError, operator.eq, a, b) + self.assertRaises(RecursionError, operator.ne, a, b) + self.assertRaises(RecursionError, operator.lt, a, b) + self.assertRaises(RecursionError, operator.le, a, b) + self.assertRaises(RecursionError, operator.gt, a, b) + self.assertRaises(RecursionError, operator.ge, a, b) b.append(17) # Even recursive lists of different lengths are different, # but they cannot be ordered self.assertTrue(not (a == b)) self.assertTrue(a != b) - self.assertRaises(RuntimeError, operator.lt, a, b) - self.assertRaises(RuntimeError, operator.le, a, b) - self.assertRaises(RuntimeError, operator.gt, a, b) - self.assertRaises(RuntimeError, operator.ge, a, b) + self.assertRaises(RecursionError, operator.lt, a, b) + self.assertRaises(RecursionError, operator.le, a, b) + self.assertRaises(RecursionError, operator.gt, a, b) + self.assertRaises(RecursionError, operator.ge, a, b) a.append(17) - self.assertRaises(RuntimeError, operator.eq, a, b) - self.assertRaises(RuntimeError, operator.ne, a, b) + self.assertRaises(RecursionError, operator.eq, a, b) + self.assertRaises(RecursionError, operator.ne, a, b) a.insert(0, 11) b.insert(0, 12) self.assertTrue(not (a == b)) diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -673,7 +673,7 @@ script_name = self._make_test_script(script_dir, mod_name, source) zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) msg = "recursion depth exceeded" - self.assertRaisesRegex(RuntimeError, msg, run_path, zip_name) + self.assertRaisesRegex(RecursionError, msg, run_path, zip_name) def test_encoding(self): with temp_dir() as script_dir: 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 @@ -211,8 +211,8 @@ for i in (50, 1000): # Issue #5392: stack overflow after hitting recursion limit twice sys.setrecursionlimit(i) - self.assertRaises(RuntimeError, f) - self.assertRaises(RuntimeError, f) + self.assertRaises(RecursionError, f) + self.assertRaises(RecursionError, f) finally: sys.setrecursionlimit(oldlimit) @@ -225,7 +225,7 @@ def f(): try: f() - except RuntimeError: + except RecursionError: f() sys.setrecursionlimit(%d) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -945,7 +945,7 @@ def outer(): try: recurse() - except RuntimeError: + except RecursionError: pass w = threading.Thread(target=outer) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,8 @@ - Issue #24450: Add gi_yieldfrom to generators and cr_await to coroutines. Contributed by Benno Leslie and Yury Selivanov. +- Issue #19235: Add new RecursionError exception. Patch by Georg Brandl. + Library ------- diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3622,7 +3622,7 @@ >>> pickle.dumps(1+2j) Traceback (most recent call last): ... - RuntimeError: maximum recursion depth exceeded + RecursionError: maximum recursion depth exceeded Removing the complex class from copyreg.dispatch_table made the __reduce_ex__() method emit another complex object: diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -497,8 +497,9 @@ { switch (status) { case SRE_ERROR_RECURSION_LIMIT: + /* This error code seems to be unused. */ PyErr_SetString( - PyExc_RuntimeError, + PyExc_RecursionError, "maximum recursion limit exceeded" ); break; diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1231,6 +1231,11 @@ SimpleExtendsException(PyExc_Exception, RuntimeError, "Unspecified run-time error."); +/* + * RecursionError extends RuntimeError + */ +SimpleExtendsException(PyExc_RuntimeError, RecursionError, + "Recursion limit exceeded."); /* * NotImplementedError extends RuntimeError @@ -2380,7 +2385,7 @@ -/* Pre-computed RuntimeError instance for when recursion depth is reached. +/* Pre-computed RecursionError instance for when recursion depth is reached. Meant to be used when normalizing the exception for exceeding the recursion depth will cause its own infinite recursion. */ @@ -2484,6 +2489,7 @@ PRE_INIT(OSError) PRE_INIT(EOFError) PRE_INIT(RuntimeError) + PRE_INIT(RecursionError) PRE_INIT(NotImplementedError) PRE_INIT(NameError) PRE_INIT(UnboundLocalError) @@ -2560,6 +2566,7 @@ #endif POST_INIT(EOFError) POST_INIT(RuntimeError) + POST_INIT(RecursionError) POST_INIT(NotImplementedError) POST_INIT(NameError) POST_INIT(UnboundLocalError) @@ -2643,9 +2650,9 @@ preallocate_memerrors(); if (!PyExc_RecursionErrorInst) { - PyExc_RecursionErrorInst = BaseException_new(&_PyExc_RuntimeError, NULL, NULL); + PyExc_RecursionErrorInst = BaseException_new(&_PyExc_RecursionError, NULL, NULL); if (!PyExc_RecursionErrorInst) - Py_FatalError("Cannot pre-allocate RuntimeError instance for " + Py_FatalError("Cannot pre-allocate RecursionError instance for " "recursion errors"); else { PyBaseExceptionObject *err_inst = @@ -2654,15 +2661,15 @@ PyObject *exc_message; exc_message = PyUnicode_FromString("maximum recursion depth exceeded"); if (!exc_message) - Py_FatalError("cannot allocate argument for RuntimeError " + Py_FatalError("cannot allocate argument for RecursionError " "pre-allocation"); args_tuple = PyTuple_Pack(1, exc_message); if (!args_tuple) - Py_FatalError("cannot allocate tuple for RuntimeError " + Py_FatalError("cannot allocate tuple for RecursionError " "pre-allocation"); Py_DECREF(exc_message); if (BaseException_init(err_inst, args_tuple, NULL)) - Py_FatalError("init of pre-allocated RuntimeError failed"); + Py_FatalError("init of pre-allocated RecursionError failed"); Py_DECREF(args_tuple); } } diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4142,7 +4142,7 @@ * were implemented in the same function: * - trying to pickle an object with a custom __reduce__ method that * fell back to object.__reduce__ in certain circumstances led to - * infinite recursion at Python level and eventual RuntimeError. + * infinite recursion at Python level and eventual RecursionError. * - Pickling objects that lied about their type by overwriting the * __class__ descriptor could lead to infinite recursion at C level * and eventual segfault. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -737,7 +737,7 @@ if (tstate->recursion_depth > recursion_limit) { --tstate->recursion_depth; tstate->overflowed = 1; - PyErr_Format(PyExc_RuntimeError, + PyErr_Format(PyExc_RecursionError, "maximum recursion depth exceeded%s", where); return -1; diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -319,7 +319,7 @@ Py_DECREF(*exc); Py_DECREF(*val); /* ... and use the recursion error instead */ - *exc = PyExc_RuntimeError; + *exc = PyExc_RecursionError; *val = PyExc_RecursionErrorInst; Py_INCREF(*exc); Py_INCREF(*val); diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1135,7 +1135,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) { if (++st->recursion_depth > st->recursion_limit) { - PyErr_SetString(PyExc_RuntimeError, + PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); VISIT_QUIT(st, 0); } @@ -1357,7 +1357,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e) { if (++st->recursion_depth > st->recursion_limit) { - PyErr_SetString(PyExc_RuntimeError, + PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); VISIT_QUIT(st, 0); } diff --git a/Tools/scripts/find_recursionlimit.py b/Tools/scripts/find_recursionlimit.py --- a/Tools/scripts/find_recursionlimit.py +++ b/Tools/scripts/find_recursionlimit.py @@ -92,7 +92,7 @@ def test_compiler_recursion(): # The compiler uses a scaling factor to support additional levels # of recursion. This is a sanity check of that scaling to ensure - # it still raises RuntimeError even at higher recursion limits + # it still raises RecursionError even at higher recursion limits compile("()" * (10 * sys.getrecursionlimit()), "", "single") def check_limit(n, test_func_name): @@ -107,7 +107,7 @@ # AttributeError can be raised because of the way e.g. PyDict_GetItem() # silences all exceptions and returns NULL, which is usually interpreted # as "missing attribute". - except (RuntimeError, AttributeError): + except (RecursionError, AttributeError): pass else: print("Yikes!") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 07:12:42 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 05:12:42 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzE5MjM1?= =?utf-8?q?=3A_Add_new_RecursionError_exception=2E_Patch_by_Georg_Brandl?= =?utf-8?q?=2E?= Message-ID: <20150703051241.53360.31879@psf.io> https://hg.python.org/cpython/rev/a795cf73ce6f changeset: 96772:a795cf73ce6f branch: 3.5 parent: 96770:3555f7b5eac6 user: Yury Selivanov date: Fri Jul 03 01:04:23 2015 -0400 summary: Issue #19235: Add new RecursionError exception. Patch by Georg Brandl. files: Doc/c-api/exceptions.rst | 12 ++++++-- Doc/library/exceptions.rst | 10 ++++++ Doc/library/pickle.rst | 2 +- Doc/whatsnew/3.5.rst | 2 + Include/ceval.h | 6 ++-- Include/pyerrors.h | 1 + Lib/ctypes/test/test_as_parameter.py | 2 +- Lib/test/exception_hierarchy.txt | 1 + Lib/test/list_tests.py | 2 +- Lib/test/test_class.py | 4 +- Lib/test/test_compile.py | 2 +- Lib/test/test_copy.py | 6 ++-- Lib/test/test_descr.py | 6 ++-- Lib/test/test_dictviews.py | 2 +- Lib/test/test_exceptions.py | 13 ++++---- Lib/test/test_isinstance.py | 10 +++--- Lib/test/test_json/test_recursion.py | 12 ++++---- Lib/test/test_pickle.py | 3 +- Lib/test/test_richcmp.py | 24 ++++++++-------- Lib/test/test_runpy.py | 2 +- Lib/test/test_sys.py | 6 ++-- Lib/test/test_threading.py | 2 +- Misc/NEWS | 2 + Modules/_pickle.c | 2 +- Modules/_sre.c | 3 +- Objects/exceptions.c | 19 ++++++++---- Objects/typeobject.c | 2 +- Python/ceval.c | 2 +- Python/errors.c | 2 +- Python/symtable.c | 4 +- Tools/scripts/find_recursionlimit.py | 4 +- 31 files changed, 101 insertions(+), 69 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 @@ -683,12 +683,12 @@ sets a :exc:`MemoryError` and returns a nonzero value. The function then checks if the recursion limit is reached. If this is the - case, a :exc:`RuntimeError` is set and a nonzero value is returned. + case, a :exc:`RecursionError` is set and a nonzero value is returned. Otherwise, zero is returned. *where* should be a string such as ``" in instance check"`` to be - concatenated to the :exc:`RuntimeError` message caused by the recursion depth - limit. + concatenated to the :exc:`RecursionError` message caused by the recursion + depth limit. .. c:function:: void Py_LeaveRecursiveCall() @@ -800,6 +800,8 @@ +-----------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_ProcessLookupError` | :exc:`ProcessLookupError` | | +-----------------------------------------+---------------------------------+----------+ +| :c:data:`PyExc_RecursionError` | :exc:`RecursionError` | | ++-----------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_ReferenceError` | :exc:`ReferenceError` | \(2) | +-----------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_RuntimeError` | :exc:`RuntimeError` | | @@ -829,6 +831,9 @@ :c:data:`PyExc_PermissionError`, :c:data:`PyExc_ProcessLookupError` and :c:data:`PyExc_TimeoutError` were introduced following :pep:`3151`. +.. versionadded:: 3.5 + :c:data:`PyExc_RecursionError`. + These are compatibility aliases to :c:data:`PyExc_OSError`: @@ -877,6 +882,7 @@ single: PyExc_OverflowError single: PyExc_PermissionError single: PyExc_ProcessLookupError + single: PyExc_RecursionError single: PyExc_ReferenceError single: PyExc_RuntimeError single: PyExc_SyntaxError diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -282,6 +282,16 @@ handling in C, most floating point operations are not checked. +.. exception:: RecursionError + + This exception is derived from :exc:`RuntimeError`. It is raised when the + interpreter detects that the maximum recursion depth (see + :func:`sys.getrecursionlimit`) is exceeded. + + .. versionadded:: 3.5 + Previously, a plain :exc:`RuntimeError` was raised. + + .. exception:: ReferenceError This exception is raised when a weak reference proxy, created by the diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -425,7 +425,7 @@ Attempts to pickle unpicklable objects will raise the :exc:`PicklingError` exception; when this happens, an unspecified number of bytes may have already been written to the underlying file. Trying to pickle a highly recursive data -structure may exceed the maximum recursion depth, a :exc:`RuntimeError` will be +structure may exceed the maximum recursion depth, a :exc:`RecursionError` will be raised in this case. You can carefully raise this limit with :func:`sys.setrecursionlimit`. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -87,6 +87,8 @@ * Generators have new ``gi_yieldfrom`` attribute, which returns the object being iterated by ``yield from`` expressions. (Contributed by Benno Leslie and Yury Selivanov in :issue:`24450`.) +* New :exc:`RecursionError` exception. (Contributed by Georg Brandl + in :issue:`19235`.) Implementation improvements: diff --git a/Include/ceval.h b/Include/ceval.h --- a/Include/ceval.h +++ b/Include/ceval.h @@ -48,16 +48,16 @@ In Python 3.0, this protection has two levels: * normal anti-recursion protection is triggered when the recursion level - exceeds the current recursion limit. It raises a RuntimeError, and sets + exceeds the current recursion limit. It raises a RecursionError, and sets the "overflowed" flag in the thread state structure. This flag temporarily *disables* the normal protection; this allows cleanup code to potentially outgrow the recursion limit while processing the - RuntimeError. + RecursionError. * "last chance" anti-recursion protection is triggered when the recursion level exceeds "current recursion limit + 50". By construction, this protection can only be triggered when the "overflowed" flag is set. It means the cleanup code has itself gone into an infinite loop, or the - RuntimeError has been mistakingly ignored. When this protection is + RecursionError has been mistakingly ignored. When this protection is triggered, the interpreter aborts with a Fatal Error. In addition, the "overflowed" flag is automatically reset when the diff --git a/Include/pyerrors.h b/Include/pyerrors.h --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -167,6 +167,7 @@ PyAPI_DATA(PyObject *) PyExc_NameError; PyAPI_DATA(PyObject *) PyExc_OverflowError; PyAPI_DATA(PyObject *) PyExc_RuntimeError; +PyAPI_DATA(PyObject *) PyExc_RecursionError; PyAPI_DATA(PyObject *) PyExc_NotImplementedError; PyAPI_DATA(PyObject *) PyExc_SyntaxError; PyAPI_DATA(PyObject *) PyExc_IndentationError; diff --git a/Lib/ctypes/test/test_as_parameter.py b/Lib/ctypes/test/test_as_parameter.py --- a/Lib/ctypes/test/test_as_parameter.py +++ b/Lib/ctypes/test/test_as_parameter.py @@ -194,7 +194,7 @@ a = A() a._as_parameter_ = a - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): c_int.from_param(a) 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 @@ -39,6 +39,7 @@ +-- ReferenceError +-- RuntimeError | +-- NotImplementedError + | +-- RecursionError +-- SyntaxError | +-- IndentationError | +-- TabError diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py --- a/Lib/test/list_tests.py +++ b/Lib/test/list_tests.py @@ -56,7 +56,7 @@ l0 = [] for i in range(sys.getrecursionlimit() + 100): l0 = [l0] - self.assertRaises(RuntimeError, repr, l0) + self.assertRaises(RecursionError, repr, l0) def test_print(self): d = self.type2test(range(200)) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -500,10 +500,10 @@ try: a() # This should not segfault - except RuntimeError: + except RecursionError: pass else: - self.fail("Failed to raise RuntimeError") + self.fail("Failed to raise RecursionError") def testForExceptionsRaisedInInstanceGetattr2(self): # Tests for exceptions raised in instance_getattr2(). diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -534,7 +534,7 @@ broken = prefix + repeated * fail_depth details = "Compiling ({!r} + {!r} * {})".format( prefix, repeated, fail_depth) - with self.assertRaises(RuntimeError, msg=details): + with self.assertRaises(RecursionError, msg=details): self.compile_single(broken) check_limit("a", "()") diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py --- a/Lib/test/test_copy.py +++ b/Lib/test/test_copy.py @@ -327,7 +327,7 @@ x.append(x) y = copy.deepcopy(x) for op in comparisons: - self.assertRaises(RuntimeError, op, y, x) + self.assertRaises(RecursionError, op, y, x) self.assertIsNot(y, x) self.assertIs(y[0], y) self.assertEqual(len(y), 1) @@ -354,7 +354,7 @@ x[0].append(x) y = copy.deepcopy(x) for op in comparisons: - self.assertRaises(RuntimeError, op, y, x) + self.assertRaises(RecursionError, op, y, x) self.assertIsNot(y, x) self.assertIsNot(y[0], x[0]) self.assertIs(y[0][0], y) @@ -373,7 +373,7 @@ for op in order_comparisons: self.assertRaises(TypeError, op, y, x) for op in equality_comparisons: - self.assertRaises(RuntimeError, op, y, x) + self.assertRaises(RecursionError, op, y, x) self.assertIsNot(y, x) self.assertIs(y['foo'], y) self.assertEqual(len(y), 1) 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 @@ -3342,7 +3342,7 @@ A.__call__ = A() try: A()() - except RuntimeError: + except RecursionError: pass else: self.fail("Recursion limit should have been reached for __call__()") @@ -4317,8 +4317,8 @@ pass Foo.__repr__ = Foo.__str__ foo = Foo() - self.assertRaises(RuntimeError, str, foo) - self.assertRaises(RuntimeError, repr, foo) + self.assertRaises(RecursionError, str, foo) + self.assertRaises(RecursionError, repr, foo) def test_mixing_slot_wrappers(self): class X(dict): diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py --- a/Lib/test/test_dictviews.py +++ b/Lib/test/test_dictviews.py @@ -195,7 +195,7 @@ def test_recursive_repr(self): d = {} d[42] = d.values() - self.assertRaises(RuntimeError, repr, d) + self.assertRaises(RecursionError, repr, d) if __name__ == "__main__": 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 @@ -84,6 +84,7 @@ x += x # this simply shouldn't blow up self.raise_catch(RuntimeError, "RuntimeError") + self.raise_catch(RecursionError, "RecursionError") self.raise_catch(SyntaxError, "SyntaxError") try: exec('/\n') @@ -474,14 +475,14 @@ def testInfiniteRecursion(self): def f(): return f() - self.assertRaises(RuntimeError, f) + self.assertRaises(RecursionError, f) def g(): try: return g() except ValueError: return -1 - self.assertRaises(RuntimeError, g) + self.assertRaises(RecursionError, g) def test_str(self): # Make sure both instances and classes have a str representation. @@ -887,10 +888,10 @@ def g(): try: return g() - except RuntimeError: + except RecursionError: return sys.exc_info() e, v, tb = g() - self.assertTrue(isinstance(v, RuntimeError), type(v)) + self.assertTrue(isinstance(v, RecursionError), type(v)) self.assertIn("maximum recursion depth exceeded", str(v)) @@ -989,10 +990,10 @@ # We cannot use assertRaises since it manually deletes the traceback try: inner() - except RuntimeError as e: + except RecursionError as e: self.assertNotEqual(wr(), None) else: - self.fail("RuntimeError not raised") + self.fail("RecursionError not raised") self.assertEqual(wr(), None) def test_errno_ENOTDIR(self): diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py --- a/Lib/test/test_isinstance.py +++ b/Lib/test/test_isinstance.py @@ -258,18 +258,18 @@ self.assertEqual(True, issubclass(str, (str, (Child, NewChild, str)))) def test_subclass_recursion_limit(self): - # make sure that issubclass raises RuntimeError before the C stack is + # make sure that issubclass raises RecursionError before the C stack is # blown - self.assertRaises(RuntimeError, blowstack, issubclass, str, str) + self.assertRaises(RecursionError, blowstack, issubclass, str, str) def test_isinstance_recursion_limit(self): - # make sure that issubclass raises RuntimeError before the C stack is + # make sure that issubclass raises RecursionError before the C stack is # blown - self.assertRaises(RuntimeError, blowstack, isinstance, '', str) + self.assertRaises(RecursionError, blowstack, isinstance, '', str) def blowstack(fxn, arg, compare_to): # Make sure that calling isinstance with a deeply nested tuple for its - # argument will raise RuntimeError eventually. + # argument will raise RecursionError eventually. tuple_arg = (compare_to,) for cnt in range(sys.getrecursionlimit()+5): tuple_arg = (tuple_arg,) diff --git a/Lib/test/test_json/test_recursion.py b/Lib/test/test_json/test_recursion.py --- a/Lib/test/test_json/test_recursion.py +++ b/Lib/test/test_json/test_recursion.py @@ -68,11 +68,11 @@ def test_highly_nested_objects_decoding(self): # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.loads('{"a":' * 100000 + '1' + '}' * 100000) - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.loads('{"a":' * 100000 + '[1]' + '}' * 100000) - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.loads('[' * 100000 + '1' + ']' * 100000) def test_highly_nested_objects_encoding(self): @@ -80,9 +80,9 @@ l, d = [], {} for x in range(100000): l, d = [l], {'k':d} - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.dumps(l) - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): self.dumps(d) def test_endless_recursion(self): @@ -92,7 +92,7 @@ """If check_circular is False, this will keep adding another list.""" return [o] - with self.assertRaises(RuntimeError): + with self.assertRaises(RecursionError): EndlessJSONEncoder(check_circular=False).encode(5j) 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 @@ -353,7 +353,8 @@ with self.subTest(name): if exc in (BlockingIOError, ResourceWarning, - StopAsyncIteration): + StopAsyncIteration, + RecursionError): continue if exc is not OSError and issubclass(exc, OSError): self.assertEqual(reverse_mapping('builtins', name), diff --git a/Lib/test/test_richcmp.py b/Lib/test/test_richcmp.py --- a/Lib/test/test_richcmp.py +++ b/Lib/test/test_richcmp.py @@ -228,25 +228,25 @@ b = UserList() a.append(b) b.append(a) - self.assertRaises(RuntimeError, operator.eq, a, b) - self.assertRaises(RuntimeError, operator.ne, a, b) - self.assertRaises(RuntimeError, operator.lt, a, b) - self.assertRaises(RuntimeError, operator.le, a, b) - self.assertRaises(RuntimeError, operator.gt, a, b) - self.assertRaises(RuntimeError, operator.ge, a, b) + self.assertRaises(RecursionError, operator.eq, a, b) + self.assertRaises(RecursionError, operator.ne, a, b) + self.assertRaises(RecursionError, operator.lt, a, b) + self.assertRaises(RecursionError, operator.le, a, b) + self.assertRaises(RecursionError, operator.gt, a, b) + self.assertRaises(RecursionError, operator.ge, a, b) b.append(17) # Even recursive lists of different lengths are different, # but they cannot be ordered self.assertTrue(not (a == b)) self.assertTrue(a != b) - self.assertRaises(RuntimeError, operator.lt, a, b) - self.assertRaises(RuntimeError, operator.le, a, b) - self.assertRaises(RuntimeError, operator.gt, a, b) - self.assertRaises(RuntimeError, operator.ge, a, b) + self.assertRaises(RecursionError, operator.lt, a, b) + self.assertRaises(RecursionError, operator.le, a, b) + self.assertRaises(RecursionError, operator.gt, a, b) + self.assertRaises(RecursionError, operator.ge, a, b) a.append(17) - self.assertRaises(RuntimeError, operator.eq, a, b) - self.assertRaises(RuntimeError, operator.ne, a, b) + self.assertRaises(RecursionError, operator.eq, a, b) + self.assertRaises(RecursionError, operator.ne, a, b) a.insert(0, 11) b.insert(0, 12) self.assertTrue(not (a == b)) diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -673,7 +673,7 @@ script_name = self._make_test_script(script_dir, mod_name, source) zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) msg = "recursion depth exceeded" - self.assertRaisesRegex(RuntimeError, msg, run_path, zip_name) + self.assertRaisesRegex(RecursionError, msg, run_path, zip_name) def test_encoding(self): with temp_dir() as script_dir: 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 @@ -211,8 +211,8 @@ for i in (50, 1000): # Issue #5392: stack overflow after hitting recursion limit twice sys.setrecursionlimit(i) - self.assertRaises(RuntimeError, f) - self.assertRaises(RuntimeError, f) + self.assertRaises(RecursionError, f) + self.assertRaises(RecursionError, f) finally: sys.setrecursionlimit(oldlimit) @@ -225,7 +225,7 @@ def f(): try: f() - except RuntimeError: + except RecursionError: f() sys.setrecursionlimit(%d) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -945,7 +945,7 @@ def outer(): try: recurse() - except RuntimeError: + except RecursionError: pass w = threading.Thread(target=outer) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,8 @@ - Issue #24450: Add gi_yieldfrom to generators and cr_await to coroutines. Contributed by Benno Leslie and Yury Selivanov. +- Issue #19235: Add new RecursionError exception. Patch by Georg Brandl. + Library ------- diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3622,7 +3622,7 @@ >>> pickle.dumps(1+2j) Traceback (most recent call last): ... - RuntimeError: maximum recursion depth exceeded + RecursionError: maximum recursion depth exceeded Removing the complex class from copyreg.dispatch_table made the __reduce_ex__() method emit another complex object: diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -500,8 +500,9 @@ { switch (status) { case SRE_ERROR_RECURSION_LIMIT: + /* This error code seems to be unused. */ PyErr_SetString( - PyExc_RuntimeError, + PyExc_RecursionError, "maximum recursion limit exceeded" ); break; diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1231,6 +1231,11 @@ SimpleExtendsException(PyExc_Exception, RuntimeError, "Unspecified run-time error."); +/* + * RecursionError extends RuntimeError + */ +SimpleExtendsException(PyExc_RuntimeError, RecursionError, + "Recursion limit exceeded."); /* * NotImplementedError extends RuntimeError @@ -2380,7 +2385,7 @@ -/* Pre-computed RuntimeError instance for when recursion depth is reached. +/* Pre-computed RecursionError instance for when recursion depth is reached. Meant to be used when normalizing the exception for exceeding the recursion depth will cause its own infinite recursion. */ @@ -2484,6 +2489,7 @@ PRE_INIT(OSError) PRE_INIT(EOFError) PRE_INIT(RuntimeError) + PRE_INIT(RecursionError) PRE_INIT(NotImplementedError) PRE_INIT(NameError) PRE_INIT(UnboundLocalError) @@ -2560,6 +2566,7 @@ #endif POST_INIT(EOFError) POST_INIT(RuntimeError) + POST_INIT(RecursionError) POST_INIT(NotImplementedError) POST_INIT(NameError) POST_INIT(UnboundLocalError) @@ -2643,9 +2650,9 @@ preallocate_memerrors(); if (!PyExc_RecursionErrorInst) { - PyExc_RecursionErrorInst = BaseException_new(&_PyExc_RuntimeError, NULL, NULL); + PyExc_RecursionErrorInst = BaseException_new(&_PyExc_RecursionError, NULL, NULL); if (!PyExc_RecursionErrorInst) - Py_FatalError("Cannot pre-allocate RuntimeError instance for " + Py_FatalError("Cannot pre-allocate RecursionError instance for " "recursion errors"); else { PyBaseExceptionObject *err_inst = @@ -2654,15 +2661,15 @@ PyObject *exc_message; exc_message = PyUnicode_FromString("maximum recursion depth exceeded"); if (!exc_message) - Py_FatalError("cannot allocate argument for RuntimeError " + Py_FatalError("cannot allocate argument for RecursionError " "pre-allocation"); args_tuple = PyTuple_Pack(1, exc_message); if (!args_tuple) - Py_FatalError("cannot allocate tuple for RuntimeError " + Py_FatalError("cannot allocate tuple for RecursionError " "pre-allocation"); Py_DECREF(exc_message); if (BaseException_init(err_inst, args_tuple, NULL)) - Py_FatalError("init of pre-allocated RuntimeError failed"); + Py_FatalError("init of pre-allocated RecursionError failed"); Py_DECREF(args_tuple); } } diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4142,7 +4142,7 @@ * were implemented in the same function: * - trying to pickle an object with a custom __reduce__ method that * fell back to object.__reduce__ in certain circumstances led to - * infinite recursion at Python level and eventual RuntimeError. + * infinite recursion at Python level and eventual RecursionError. * - Pickling objects that lied about their type by overwriting the * __class__ descriptor could lead to infinite recursion at C level * and eventual segfault. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -737,7 +737,7 @@ if (tstate->recursion_depth > recursion_limit) { --tstate->recursion_depth; tstate->overflowed = 1; - PyErr_Format(PyExc_RuntimeError, + PyErr_Format(PyExc_RecursionError, "maximum recursion depth exceeded%s", where); return -1; diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -319,7 +319,7 @@ Py_DECREF(*exc); Py_DECREF(*val); /* ... and use the recursion error instead */ - *exc = PyExc_RuntimeError; + *exc = PyExc_RecursionError; *val = PyExc_RecursionErrorInst; Py_INCREF(*exc); Py_INCREF(*val); diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1135,7 +1135,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) { if (++st->recursion_depth > st->recursion_limit) { - PyErr_SetString(PyExc_RuntimeError, + PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); VISIT_QUIT(st, 0); } @@ -1357,7 +1357,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e) { if (++st->recursion_depth > st->recursion_limit) { - PyErr_SetString(PyExc_RuntimeError, + PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); VISIT_QUIT(st, 0); } diff --git a/Tools/scripts/find_recursionlimit.py b/Tools/scripts/find_recursionlimit.py --- a/Tools/scripts/find_recursionlimit.py +++ b/Tools/scripts/find_recursionlimit.py @@ -92,7 +92,7 @@ def test_compiler_recursion(): # The compiler uses a scaling factor to support additional levels # of recursion. This is a sanity check of that scaling to ensure - # it still raises RuntimeError even at higher recursion limits + # it still raises RecursionError even at higher recursion limits compile("()" * (10 * sys.getrecursionlimit()), "", "single") def check_limit(n, test_func_name): @@ -107,7 +107,7 @@ # AttributeError can be raised because of the way e.g. PyDict_GetItem() # silences all exceptions and returns NULL, which is usually interpreted # as "missing attribute". - except (RuntimeError, AttributeError): + except (RecursionError, AttributeError): pass else: print("Yikes!") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 07:16:26 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 05:16:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Add_a_rudiment?= =?utf-8?q?ary_test_for_StopAsyncIteration_in_test=5Fexceptions=2E?= Message-ID: <20150703051624.37559.23445@psf.io> https://hg.python.org/cpython/rev/7edbbcbf5936 changeset: 96774:7edbbcbf5936 branch: 3.5 parent: 96772:a795cf73ce6f user: Yury Selivanov date: Fri Jul 03 01:16:04 2015 -0400 summary: Add a rudimentary test for StopAsyncIteration in test_exceptions. files: Lib/test/test_exceptions.py | 2 ++ 1 files changed, 2 insertions(+), 0 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 @@ -118,6 +118,8 @@ try: x = 1/0 except Exception as e: pass + self.raise_catch(StopAsyncIteration, "StopAsyncIteration") + def testSyntaxErrorMessage(self): # make sure the right exception message is raised for each of # these code fragments -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 07:16:26 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 05:16:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41?= Message-ID: <20150703051624.9573.86048@psf.io> https://hg.python.org/cpython/rev/09b223827f63 changeset: 96775:09b223827f63 parent: 96773:749d74e5dfa7 parent: 96774:7edbbcbf5936 user: Yury Selivanov date: Fri Jul 03 01:16:20 2015 -0400 summary: Merge 3.5 files: Lib/test/test_exceptions.py | 2 ++ 1 files changed, 2 insertions(+), 0 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 @@ -118,6 +118,8 @@ try: x = 1/0 except Exception as e: pass + self.raise_catch(StopAsyncIteration, "StopAsyncIteration") + def testSyntaxErrorMessage(self): # make sure the right exception message is raised for each of # these code fragments -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 3 10:45:44 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 03 Jul 2015 08:45:44 +0000 Subject: [Python-checkins] Daily reference leaks (09b223827f63): sum=-1 Message-ID: <20150703084544.26750.81937@psf.io> results for 09b223827f63 on branch "default" -------------------------------------------- test_asyncio leaked [0, 0, 3] memory blocks, sum=3 test_collections leaked [-6, 0, 0] references, sum=-6 test_collections leaked [-3, 1, 0] memory blocks, sum=-2 test_functools leaked [0, 2, 2] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflog7TgXcD', '--timeout', '7200'] From python-checkins at python.org Fri Jul 3 11:52:15 2015 From: python-checkins at python.org (nick.coghlan) Date: Fri, 03 Jul 2015 09:52:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Merge_fix_for_=2324458_from_3=2E5?= Message-ID: <20150703095215.19983.17210@psf.io> https://hg.python.org/cpython/rev/86daa37c1cc9 changeset: 96777:86daa37c1cc9 parent: 96775:09b223827f63 parent: 96776:bad92d696866 user: Nick Coghlan date: Fri Jul 03 19:52:05 2015 +1000 summary: Merge fix for #24458 from 3.5 files: Doc/c-api/init.rst | 2 + Doc/c-api/module.rst | 320 ++++++++++++++++++----- Doc/extending/building.rst | 63 +++- Doc/extending/extending.rst | 7 + Doc/extending/windows.rst | 5 +- Doc/whatsnew/3.5.rst | 4 +- Misc/NEWS | 15 +- 7 files changed, 312 insertions(+), 104 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -873,6 +873,8 @@ instead. +.. _sub-interpreter-support: + Sub-interpreter support ======================= diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -82,6 +82,18 @@ Similar to :c:func:`PyModule_GetNameObject` but return the name encoded to ``'utf-8'``. +.. c:function:: void* PyModule_GetState(PyObject *module) + + Return the "state" of the module, that is, a pointer to the block of memory + allocated at module creation time, or *NULL*. See + :c:member:`PyModuleDef.m_size`. + + +.. c:function:: PyModuleDef* PyModule_GetDef(PyObject *module) + + Return a pointer to the :c:type:`PyModuleDef` struct from which the module was + created, or *NULL* if the module wasn't created from a definition. + .. c:function:: PyObject* PyModule_GetFilenameObject(PyObject *module) @@ -107,57 +119,25 @@ unencodable filenames, use :c:func:`PyModule_GetFilenameObject` instead. -Per-interpreter module state -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Single-phase initialization creates singleton modules that can store additional -information as part of the interpreter, allow that state to be retrieved later -with only a reference to the module definition, rather than to the module -itself. - -.. c:function:: void* PyModule_GetState(PyObject *module) - - Return the "state" of the module, that is, a pointer to the block of memory - allocated at module creation time, or *NULL*. See - :c:member:`PyModuleDef.m_size`. - - -.. c:function:: PyModuleDef* PyModule_GetDef(PyObject *module) - - Return a pointer to the :c:type:`PyModuleDef` struct from which the module was - created, or *NULL* if the module wasn't created with - :c:func:`PyModule_Create`. - -.. c:function:: PyObject* PyState_FindModule(PyModuleDef *def) - - Returns the module object that was created from *def* for the current interpreter. - This method requires that the module object has been attached to the interpreter state with - :c:func:`PyState_AddModule` beforehand. In case the corresponding module object is not - found or has not been attached to the interpreter state yet, it returns NULL. - -.. c:function:: int PyState_AddModule(PyObject *module, PyModuleDef *def) - - Attaches the module object passed to the function to the interpreter state. This allows - the module object to be accessible via - :c:func:`PyState_FindModule`. - - .. versionadded:: 3.3 - -.. c:function:: int PyState_RemoveModule(PyModuleDef *def) - - Removes the module object created from *def* from the interpreter state. - - .. versionadded:: 3.3 +.. _initializing-modules: Initializing C modules ^^^^^^^^^^^^^^^^^^^^^^ +Modules objects are usually created from extension modules (shared libraries +which export an initialization function), or compiled-in modules +(where the initialization function is added using :c:func:`PyImport_AppendInittab`). +See :ref:`building` or :ref:`extending-with-embedding` for details. + +The initialization function can either pass pass a module definition instance +to :c:func:`PyModule_Create`, and return the resulting module object, +or request "multi-phase initialization" by returning the definition struct itself. + .. c:type:: PyModuleDef - This struct holds all information that is needed to create a module object. - There is usually only one static variable of that type for each module, which - is statically initialized and then passed to :c:func:`PyModule_Create` in the - module initialization function. + The module definition struct, which holds all information needed to create + a module object. There is usually only one statically initialized variable + of this type for each module. .. c:member:: PyModuleDef_Base m_base @@ -174,19 +154,21 @@ .. c:member:: Py_ssize_t m_size - Some modules allow re-initialization (calling their ``PyInit_*`` function - more than once). These modules should keep their state in a per-module - memory area that can be retrieved with :c:func:`PyModule_GetState`. + Module state may be kept in a per-module memory area that can be + retrieved with :c:func:`PyModule_GetState`, rather than in static globals. + This makes modules safe for use in multiple sub-interpreters. - This memory should be used, rather than static globals, to hold per-module - state, since it is then safe for use in multiple sub-interpreters. It is - freed when the module object is deallocated, after the :c:member:`m_free` - function has been called, if present. + This memory area is allocated based on *m_size* on module creation, + and freed when the module object is deallocated, after the + :c:member:`m_free` function has been called, if present. - Setting ``m_size`` to ``-1`` means that the module can not be - re-initialized because it has global state. Setting it to a non-negative - value means that the module can be re-initialized and specifies the - additional amount of memory it requires for its state. + Setting ``m_size`` to ``-1`` means that the module does not support + sub-interpreters, because it has global state. + + Setting it to a non-negative value means that the module can be + re-initialized and specifies the additional amount of memory it requires + for its state. Non-negative ``m_size`` is required for multi-phase + initialization. See :PEP:`3121` for more details. @@ -198,7 +180,15 @@ .. c:member:: PyModuleDef_Slot* m_slots An array of slot definitions for multi-phase initialization, terminated by - a *NULL* entry. + a ``{0, NULL}`` entry. + When using single-phase initialization, *m_slots* must be *NULL*. + + .. versionchanged:: 3.5 + + Prior to version 3.5, this member was always set to *NULL*, + and was defined as: + + .. c:member:: inquiry m_reload .. c:member:: traverseproc m_traverse @@ -215,20 +205,23 @@ A function to call during deallocation of the module object, or *NULL* if not needed. +Single-phase initialization +........................... + The module initialization function may create and return the module object directly. This is referred to as "single-phase initialization", and uses one of the following two module creation functions: -.. c:function:: PyObject* PyModule_Create(PyModuleDef *module) +.. c:function:: PyObject* PyModule_Create(PyModuleDef *def) - Create a new module object, given the definition in *module*. This behaves + Create a new module object, given the definition in *def*. This behaves like :c:func:`PyModule_Create2` with *module_api_version* set to :const:`PYTHON_API_VERSION`. -.. c:function:: PyObject* PyModule_Create2(PyModuleDef *module, int module_api_version) +.. c:function:: PyObject* PyModule_Create2(PyModuleDef *def, int module_api_version) - Create a new module object, given the definition in *module*, assuming the + Create a new module object, given the definition in *def*, assuming the API version *module_api_version*. If that version does not match the version of the running interpreter, a :exc:`RuntimeWarning` is emitted. @@ -237,39 +230,179 @@ Most uses of this function should be using :c:func:`PyModule_Create` instead; only use this if you are sure you need it. +Before it is returned from in the initialization function, the resulting module +object is typically populated using functions like :c:func:`PyModule_AddObject`. -Alternatively, the module initialization function may instead return a -:c:type:`PyModuleDef` instance with a non-empty ``m_slots`` array. This is -referred to as "multi-phase initialization", and ``PyModuleDef`` instance -should be initialized with the following function: +.. _multi-phase-initialization: -.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *module) +Multi-phase initialization +.......................... + +An alternate way to specify extensions is to request "multi-phase initialization". +Extension modules created this way behave more like Python modules: the +initialization is split between the *creation phase*, when the module object +is created, and the *execution phase*, when it is populated. +The distinction is similar to the :py:meth:`__new__` and :py:meth:`__init__` methods +of classes. + +Unlike modules created using single-phase initialization, these modules are not +singletons: if the *sys.modules* entry is removed and the module is re-imported, +a new module object is created, and the old module is subject to normal garbage +collection -- as with Python modules. +By default, multiple modules created from the same definition should be +independent: changes to one should not affect the others. +This means that all state should be specific to the module object (using e.g. +using :c:func:`PyModule_GetState`), or its contents (such as the module's +:attr:`__dict__` or individual classes created with :c:func:`PyType_FromSpec`). + +All modules created using multi-phase initialization are expected to support +:ref:`sub-interpreters `. Making sure multiple modules +are independent is typically enough to achieve this. + +To request multi-phase initialization, the initialization function +(PyInit_modulename) returns a :c:type:`PyModuleDef` instance with non-empty +:c:member:`~PyModuleDef.m_slots`. Before it is returned, the ``PyModuleDef`` +instance must be initialized with the following function: + +.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *def) Ensures a module definition is a properly initialized Python object that correctly reports its type and reference count. -.. XXX (ncoghlan): It's not clear if it makes sense to document PyModule_ExecDef - PyModule_FromDefAndSpec or PyModule_FromDefAndSpec2 here, as end user code - generally shouldn't be calling those. + Returns *def* cast to ``PyObject*``, or *NULL* if an error occurred. -The module initialization function (if using single phase initialization) or -a function called from a module execution slot (if using multiphase -initialization), can use the following functions to help initialize the module -state: + .. versionadded:: 3.5 + +The *m_slots* member of the module definition must point to an array of +``PyModuleDef_Slot`` structures: + +.. c:type:: PyModuleDef_Slot + + .. c:member:: int slot + + A slot ID, chosen from the available values explained below. + + .. c:member:: void* value + + Value of the slot, whose meaning depends on the slot ID. + + .. versionadded:: 3.5 + +The *m_slots* array must be terminated by a slot with id 0. + +The available slot types are: + +.. c:var:: Py_mod_create + + Specifies a function that is called to create the module object itself. + The *value* pointer of this slot must point to a function of the signature: + + .. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def) + + The function receives a :py:class:`~importlib.machinery.ModuleSpec` + instance, as defined in :PEP:`451`, and the module definition. + It should return a new module object, or set an error + and return *NULL*. + + This function should be kept minimal. In particular, it should not + call arbitrary Python code, as trying to import the same module again may + result in an infinite loop. + + Multiple ``Py_mod_create`` slots may not be specified in one module + definition. + + If ``Py_mod_create`` is not specified, the import machinery will create + a normal module object using :c:func:`PyModule_New`. The name is taken from + *spec*, not the definition, to allow extension modules to dynamically adjust + to their place in the module hierarchy and be imported under different + names through symlinks, all while sharing a single module definition. + + There is no requirement for the returned object to be an instance of + :c:type:`PyModule_Type`. Any type can be used, as long as it supports + setting and getting import-related attributes. + However, only ``PyModule_Type`` instances may be returned if the + ``PyModuleDef`` has non-*NULL* ``m_methods``, ``m_traverse``, ``m_clear``, + ``m_free``; non-zero ``m_size``; or slots other than ``Py_mod_create``. + +.. c:var:: Py_mod_exec + + Specifies a function that is called to *execute* the module. + This is equivalent to executing the code of a Python module: typically, + this function adds classes and constants to the module. + The signature of the function is: + + .. c:function:: int exec_module(PyObject* module) + + If multiple ``Py_mod_exec`` slots are specified, they are processed in the + order they appear in the *m_slots* array. + +See :PEP:`489` for more details on multi-phase initialization. + +Low-level module creation functions +................................... + +The following functions are called under the hood when using multi-phase +initialization. They can be used directly, for example when creating module +objects dynamically. Note that both ``PyModule_FromDefAndSpec`` and +``PyModule_ExecDef`` must be called to fully initialize a module. + +.. c:function:: PyObject * PyModule_FromDefAndSpec(PyModuleDef *def, PyObject *spec) + + Create a new module object, given the definition in *module* and the + ModuleSpec *spec*. This behaves like :c:func:`PyModule_FromDefAndSpec2` + with *module_api_version* set to :const:`PYTHON_API_VERSION`. + + .. versionadded:: 3.5 + +.. c:function:: PyObject * PyModule_FromDefAndSpec2(PyModuleDef *def, PyObject *spec, int module_api_version) + + Create a new module object, given the definition in *module* and the + ModuleSpec *spec*, assuming the API version *module_api_version*. + If that version does not match the version of the running interpreter, + a :exc:`RuntimeWarning` is emitted. + + .. note:: + + Most uses of this function should be using :c:func:`PyModule_FromDefAndSpec` + instead; only use this if you are sure you need it. + + .. versionadded:: 3.5 + +.. c:function:: int PyModule_ExecDef(PyObject *module, PyModuleDef *def) + + Process any execution slots (:c:data:`Py_mod_exec`) given in *def*. + + .. versionadded:: 3.5 .. c:function:: int PyModule_SetDocString(PyObject *module, const char *docstring) - Set the docstring for *module* to *docstring*. Return ``-1`` on error, ``0`` - on success. + Set the docstring for *module* to *docstring*. + This function is called automatically when creating a module from + ``PyModuleDef``, using either ``PyModule_Create`` or + ``PyModule_FromDefAndSpec``. + + .. versionadded:: 3.5 .. c:function:: int PyModule_AddFunctions(PyObject *module, PyMethodDef *functions) - Add the functions from the ``NULL`` terminated *functions* array to *module*. + Add the functions from the *NULL* terminated *functions* array to *module*. Refer to the :c:type:`PyMethodDef` documentation for details on individual entries (due to the lack of a shared module namespace, module level "functions" implemented in C typically receive the module as their first parameter, making them similar to instance methods on Python classes). + This function is called automatically when creating a module from + ``PyModuleDef``, using either ``PyModule_Create`` or + ``PyModule_FromDefAndSpec``. + .. versionadded:: 3.5 + +Support functions +................. + +The module initialization function (if using single phase initialization) or +a function called from a module execution slot (if using multi-phase +initialization), can use the following functions to help initialize the module +state: .. c:function:: int PyModule_AddObject(PyObject *module, const char *name, PyObject *value) @@ -288,7 +421,7 @@ Add a string constant to *module* as *name*. This convenience function can be used from the module's initialization function. The string *value* must be - null-terminated. Return ``-1`` on error, ``0`` on success. + *NULL*-terminated. Return ``-1`` on error, ``0`` on success. .. c:function:: int PyModule_AddIntMacro(PyObject *module, macro) @@ -302,3 +435,36 @@ .. c:function:: int PyModule_AddStringMacro(PyObject *module, macro) Add a string constant to *module*. + + +Module lookup +^^^^^^^^^^^^^ + +Single-phase initialization creates singleton modules that can be looked up +in the context of the current interpreter. This allows the module object to be +retrieved later with only a reference to the module definition. + +These functions will not work on modules created using multi-phase initialization, +since multiple such modules can be created from a single definition. + +.. c:function:: PyObject* PyState_FindModule(PyModuleDef *def) + + Returns the module object that was created from *def* for the current interpreter. + This method requires that the module object has been attached to the interpreter state with + :c:func:`PyState_AddModule` beforehand. In case the corresponding module object is not + found or has not been attached to the interpreter state yet, it returns *NULL*. + +.. c:function:: int PyState_AddModule(PyObject *module, PyModuleDef *def) + + Attaches the module object passed to the function to the interpreter state. This allows + the module object to be accessible via :c:func:`PyState_FindModule`. + + Only effective on modules created using single-phase initialization. + + .. versionadded:: 3.3 + +.. c:function:: int PyState_RemoveModule(PyModuleDef *def) + + Removes the module object created from *def* from the interpreter state. + + .. versionadded:: 3.3 diff --git a/Doc/extending/building.rst b/Doc/extending/building.rst --- a/Doc/extending/building.rst +++ b/Doc/extending/building.rst @@ -1,27 +1,58 @@ .. highlightlang:: c - .. _building: -******************************************** +***************************** +Building C and C++ Extensions +***************************** + +A C extension for CPython is a shared library (e.g. a ``.so`` file on Linux, +``.pyd`` on Windows), which exports an *initialization function*. + +To be importable, the shared library must be available on :envvar:`PYTHONPATH`, +and must be named after the module name, with an appropriate extension. +When using distutils, the correct filename is generated automatically. + +The initialization function has the signature: + +.. c:function:: PyObject* PyInit_modulename(void) + +It returns either a fully-initialized module, or a :c:type:`PyModuleDef` +instance. See :ref:`initializing-modules` for details. + +.. highlightlang:: python + +For modules with ASCII-only names, the function must be named +``PyInit_``, with ```` replaced by the name of the +module. When using :ref:`multi-phase-initialization`, non-ASCII module names +are allowed. In this case, the initialization function name is +``PyInitU_``, with ```` encoded using Python's +*punycode* encoding with hyphens replaced by underscores. In Python:: + + def initfunc_name(name): + try: + suffix = b'_' + name.encode('ascii') + except UnicodeEncodeError: + suffix = b'U_' + name.encode('punycode').replace(b'-', b'_') + return b'PyInit' + suffix + +It is possible to export multiple modules from a single shared library by +defining multiple initialization functions. However, importing them requires +using symbolic links or a custom importer, because by default only the +function corresponding to the filename is found. +See :PEP:`489#multiple-modules-in-one-library` for details. + + +.. highlightlang:: c + Building C and C++ Extensions with distutils -******************************************** +============================================ .. sectionauthor:: Martin v. L?wis - -Starting in Python 1.4, Python provides, on Unix, a special make file for -building make files for building dynamically-linked extensions and custom -interpreters. Starting with Python 2.0, this mechanism (known as related to -Makefile.pre.in, and Setup files) is no longer supported. Building custom -interpreters was rarely used, and extension modules can be built using -distutils. - -Building an extension module using distutils requires that distutils is -installed on the build machine, which is included in Python 2.x and available -separately for Python 1.5. Since distutils also supports creation of binary -packages, users don't necessarily need a compiler and distutils to install the -extension. +Extension modules can be built using distutils, which is included in Python. +Since distutils also supports creation of binary packages, users don't +necessarily need a compiler and distutils to install the extension. A distutils package contains a driver script, :file:`setup.py`. This is a plain Python file, which, in the most simple case, could look like this:: diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -413,6 +413,13 @@ as :file:`Modules/xxmodule.c`. This file may be used as a template or simply read as an example. +.. note:: + + Unlike our ``spam`` example, ``xxmodule`` uses *multi-phase initialization* + (new in Python 3.5), where a PyModuleDef structure is returned from + ``PyInit_spam``, and creation of the module is left to the import machinery. + For details on multi-phase initialization, see :PEP:`489`. + .. _compilation: diff --git a/Doc/extending/windows.rst b/Doc/extending/windows.rst --- a/Doc/extending/windows.rst +++ b/Doc/extending/windows.rst @@ -98,9 +98,8 @@ it. Copy your C sources into it. Note that the module source file name does not necessarily have to match the module name, but the name of the initialization function should match the module name --- you can only import a - module :mod:`spam` if its initialization function is called :c:func:`initspam`, - and it should call :c:func:`Py_InitModule` with the string ``"spam"`` as its - first argument (use the minimal :file:`example.c` in this directory as a guide). + module :mod:`spam` if its initialization function is called :c:func:`PyInit_spam`, + (see :ref:`building`, or use the minimal :file:`Modules/xxmodule.c` as a guide). By convention, it lives in a file called :file:`spam.c` or :file:`spammodule.c`. The output file should be called :file:`spam.pyd` (in Release mode) or :file:`spam_d.pyd` (in Debug mode). The extension :file:`.pyd` was chosen diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -283,7 +283,7 @@ This change brings the import semantics of extension modules that opt-in to using the new mechanism much closer to those of Python source and bytecode -modules, including the ability to any valid identifier as a module name, +modules, including the ability to use any valid identifier as a module name, rather than being restricted to ASCII. .. seealso:: @@ -763,7 +763,7 @@ ----------- * The :mod:`unicodedata` module now uses data from `Unicode 8.0.0 -`_. + `_. wsgiref diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,12 +17,6 @@ for patterns that starts with capturing groups. Fast searching optimization now can't be disabled at compile time. -Documentation -------------- - -- Issue #24351: Clarify what is meant by "identifier" in the context of - string.Template instances. - What's New in Python 3.5.0 beta 3? ================================== @@ -111,6 +105,15 @@ tp_finalize to avoid reference leaks encountered when combining tp_dealloc with PyType_FromSpec (see issue #16690 for details) +Documentation +------------- + +- Issue #24458: Update documentation to cover multi-phase initialization for + extension modules (PEP 489). Patch by Petr Viktorin. + +- Issue #24351: Clarify what is meant by "identifier" in the context of + string.Template instances. + What's New in Python 3.5.0 beta 2? ================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 11:52:15 2015 From: python-checkins at python.org (nick.coghlan) Date: Fri, 03 Jul 2015 09:52:15 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogQ2xvc2UgIzI0NDU4?= =?utf-8?q?=3A_PEP_489_documentation?= Message-ID: <20150703095215.17196.61460@psf.io> https://hg.python.org/cpython/rev/bad92d696866 changeset: 96776:bad92d696866 branch: 3.5 parent: 96774:7edbbcbf5936 user: Nick Coghlan date: Fri Jul 03 19:49:15 2015 +1000 summary: Close #24458: PEP 489 documentation Patch by Petr Viktorin. files: Doc/c-api/init.rst | 2 + Doc/c-api/module.rst | 320 ++++++++++++++++++----- Doc/extending/building.rst | 63 +++- Doc/extending/extending.rst | 7 + Doc/extending/windows.rst | 5 +- Doc/whatsnew/3.5.rst | 4 +- Misc/NEWS | 3 + 7 files changed, 306 insertions(+), 98 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -873,6 +873,8 @@ instead. +.. _sub-interpreter-support: + Sub-interpreter support ======================= diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -82,6 +82,18 @@ Similar to :c:func:`PyModule_GetNameObject` but return the name encoded to ``'utf-8'``. +.. c:function:: void* PyModule_GetState(PyObject *module) + + Return the "state" of the module, that is, a pointer to the block of memory + allocated at module creation time, or *NULL*. See + :c:member:`PyModuleDef.m_size`. + + +.. c:function:: PyModuleDef* PyModule_GetDef(PyObject *module) + + Return a pointer to the :c:type:`PyModuleDef` struct from which the module was + created, or *NULL* if the module wasn't created from a definition. + .. c:function:: PyObject* PyModule_GetFilenameObject(PyObject *module) @@ -107,57 +119,25 @@ unencodable filenames, use :c:func:`PyModule_GetFilenameObject` instead. -Per-interpreter module state -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Single-phase initialization creates singleton modules that can store additional -information as part of the interpreter, allow that state to be retrieved later -with only a reference to the module definition, rather than to the module -itself. - -.. c:function:: void* PyModule_GetState(PyObject *module) - - Return the "state" of the module, that is, a pointer to the block of memory - allocated at module creation time, or *NULL*. See - :c:member:`PyModuleDef.m_size`. - - -.. c:function:: PyModuleDef* PyModule_GetDef(PyObject *module) - - Return a pointer to the :c:type:`PyModuleDef` struct from which the module was - created, or *NULL* if the module wasn't created with - :c:func:`PyModule_Create`. - -.. c:function:: PyObject* PyState_FindModule(PyModuleDef *def) - - Returns the module object that was created from *def* for the current interpreter. - This method requires that the module object has been attached to the interpreter state with - :c:func:`PyState_AddModule` beforehand. In case the corresponding module object is not - found or has not been attached to the interpreter state yet, it returns NULL. - -.. c:function:: int PyState_AddModule(PyObject *module, PyModuleDef *def) - - Attaches the module object passed to the function to the interpreter state. This allows - the module object to be accessible via - :c:func:`PyState_FindModule`. - - .. versionadded:: 3.3 - -.. c:function:: int PyState_RemoveModule(PyModuleDef *def) - - Removes the module object created from *def* from the interpreter state. - - .. versionadded:: 3.3 +.. _initializing-modules: Initializing C modules ^^^^^^^^^^^^^^^^^^^^^^ +Modules objects are usually created from extension modules (shared libraries +which export an initialization function), or compiled-in modules +(where the initialization function is added using :c:func:`PyImport_AppendInittab`). +See :ref:`building` or :ref:`extending-with-embedding` for details. + +The initialization function can either pass pass a module definition instance +to :c:func:`PyModule_Create`, and return the resulting module object, +or request "multi-phase initialization" by returning the definition struct itself. + .. c:type:: PyModuleDef - This struct holds all information that is needed to create a module object. - There is usually only one static variable of that type for each module, which - is statically initialized and then passed to :c:func:`PyModule_Create` in the - module initialization function. + The module definition struct, which holds all information needed to create + a module object. There is usually only one statically initialized variable + of this type for each module. .. c:member:: PyModuleDef_Base m_base @@ -174,19 +154,21 @@ .. c:member:: Py_ssize_t m_size - Some modules allow re-initialization (calling their ``PyInit_*`` function - more than once). These modules should keep their state in a per-module - memory area that can be retrieved with :c:func:`PyModule_GetState`. + Module state may be kept in a per-module memory area that can be + retrieved with :c:func:`PyModule_GetState`, rather than in static globals. + This makes modules safe for use in multiple sub-interpreters. - This memory should be used, rather than static globals, to hold per-module - state, since it is then safe for use in multiple sub-interpreters. It is - freed when the module object is deallocated, after the :c:member:`m_free` - function has been called, if present. + This memory area is allocated based on *m_size* on module creation, + and freed when the module object is deallocated, after the + :c:member:`m_free` function has been called, if present. - Setting ``m_size`` to ``-1`` means that the module can not be - re-initialized because it has global state. Setting it to a non-negative - value means that the module can be re-initialized and specifies the - additional amount of memory it requires for its state. + Setting ``m_size`` to ``-1`` means that the module does not support + sub-interpreters, because it has global state. + + Setting it to a non-negative value means that the module can be + re-initialized and specifies the additional amount of memory it requires + for its state. Non-negative ``m_size`` is required for multi-phase + initialization. See :PEP:`3121` for more details. @@ -198,7 +180,15 @@ .. c:member:: PyModuleDef_Slot* m_slots An array of slot definitions for multi-phase initialization, terminated by - a *NULL* entry. + a ``{0, NULL}`` entry. + When using single-phase initialization, *m_slots* must be *NULL*. + + .. versionchanged:: 3.5 + + Prior to version 3.5, this member was always set to *NULL*, + and was defined as: + + .. c:member:: inquiry m_reload .. c:member:: traverseproc m_traverse @@ -215,20 +205,23 @@ A function to call during deallocation of the module object, or *NULL* if not needed. +Single-phase initialization +........................... + The module initialization function may create and return the module object directly. This is referred to as "single-phase initialization", and uses one of the following two module creation functions: -.. c:function:: PyObject* PyModule_Create(PyModuleDef *module) +.. c:function:: PyObject* PyModule_Create(PyModuleDef *def) - Create a new module object, given the definition in *module*. This behaves + Create a new module object, given the definition in *def*. This behaves like :c:func:`PyModule_Create2` with *module_api_version* set to :const:`PYTHON_API_VERSION`. -.. c:function:: PyObject* PyModule_Create2(PyModuleDef *module, int module_api_version) +.. c:function:: PyObject* PyModule_Create2(PyModuleDef *def, int module_api_version) - Create a new module object, given the definition in *module*, assuming the + Create a new module object, given the definition in *def*, assuming the API version *module_api_version*. If that version does not match the version of the running interpreter, a :exc:`RuntimeWarning` is emitted. @@ -237,39 +230,179 @@ Most uses of this function should be using :c:func:`PyModule_Create` instead; only use this if you are sure you need it. +Before it is returned from in the initialization function, the resulting module +object is typically populated using functions like :c:func:`PyModule_AddObject`. -Alternatively, the module initialization function may instead return a -:c:type:`PyModuleDef` instance with a non-empty ``m_slots`` array. This is -referred to as "multi-phase initialization", and ``PyModuleDef`` instance -should be initialized with the following function: +.. _multi-phase-initialization: -.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *module) +Multi-phase initialization +.......................... + +An alternate way to specify extensions is to request "multi-phase initialization". +Extension modules created this way behave more like Python modules: the +initialization is split between the *creation phase*, when the module object +is created, and the *execution phase*, when it is populated. +The distinction is similar to the :py:meth:`__new__` and :py:meth:`__init__` methods +of classes. + +Unlike modules created using single-phase initialization, these modules are not +singletons: if the *sys.modules* entry is removed and the module is re-imported, +a new module object is created, and the old module is subject to normal garbage +collection -- as with Python modules. +By default, multiple modules created from the same definition should be +independent: changes to one should not affect the others. +This means that all state should be specific to the module object (using e.g. +using :c:func:`PyModule_GetState`), or its contents (such as the module's +:attr:`__dict__` or individual classes created with :c:func:`PyType_FromSpec`). + +All modules created using multi-phase initialization are expected to support +:ref:`sub-interpreters `. Making sure multiple modules +are independent is typically enough to achieve this. + +To request multi-phase initialization, the initialization function +(PyInit_modulename) returns a :c:type:`PyModuleDef` instance with non-empty +:c:member:`~PyModuleDef.m_slots`. Before it is returned, the ``PyModuleDef`` +instance must be initialized with the following function: + +.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *def) Ensures a module definition is a properly initialized Python object that correctly reports its type and reference count. -.. XXX (ncoghlan): It's not clear if it makes sense to document PyModule_ExecDef - PyModule_FromDefAndSpec or PyModule_FromDefAndSpec2 here, as end user code - generally shouldn't be calling those. + Returns *def* cast to ``PyObject*``, or *NULL* if an error occurred. -The module initialization function (if using single phase initialization) or -a function called from a module execution slot (if using multiphase -initialization), can use the following functions to help initialize the module -state: + .. versionadded:: 3.5 + +The *m_slots* member of the module definition must point to an array of +``PyModuleDef_Slot`` structures: + +.. c:type:: PyModuleDef_Slot + + .. c:member:: int slot + + A slot ID, chosen from the available values explained below. + + .. c:member:: void* value + + Value of the slot, whose meaning depends on the slot ID. + + .. versionadded:: 3.5 + +The *m_slots* array must be terminated by a slot with id 0. + +The available slot types are: + +.. c:var:: Py_mod_create + + Specifies a function that is called to create the module object itself. + The *value* pointer of this slot must point to a function of the signature: + + .. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def) + + The function receives a :py:class:`~importlib.machinery.ModuleSpec` + instance, as defined in :PEP:`451`, and the module definition. + It should return a new module object, or set an error + and return *NULL*. + + This function should be kept minimal. In particular, it should not + call arbitrary Python code, as trying to import the same module again may + result in an infinite loop. + + Multiple ``Py_mod_create`` slots may not be specified in one module + definition. + + If ``Py_mod_create`` is not specified, the import machinery will create + a normal module object using :c:func:`PyModule_New`. The name is taken from + *spec*, not the definition, to allow extension modules to dynamically adjust + to their place in the module hierarchy and be imported under different + names through symlinks, all while sharing a single module definition. + + There is no requirement for the returned object to be an instance of + :c:type:`PyModule_Type`. Any type can be used, as long as it supports + setting and getting import-related attributes. + However, only ``PyModule_Type`` instances may be returned if the + ``PyModuleDef`` has non-*NULL* ``m_methods``, ``m_traverse``, ``m_clear``, + ``m_free``; non-zero ``m_size``; or slots other than ``Py_mod_create``. + +.. c:var:: Py_mod_exec + + Specifies a function that is called to *execute* the module. + This is equivalent to executing the code of a Python module: typically, + this function adds classes and constants to the module. + The signature of the function is: + + .. c:function:: int exec_module(PyObject* module) + + If multiple ``Py_mod_exec`` slots are specified, they are processed in the + order they appear in the *m_slots* array. + +See :PEP:`489` for more details on multi-phase initialization. + +Low-level module creation functions +................................... + +The following functions are called under the hood when using multi-phase +initialization. They can be used directly, for example when creating module +objects dynamically. Note that both ``PyModule_FromDefAndSpec`` and +``PyModule_ExecDef`` must be called to fully initialize a module. + +.. c:function:: PyObject * PyModule_FromDefAndSpec(PyModuleDef *def, PyObject *spec) + + Create a new module object, given the definition in *module* and the + ModuleSpec *spec*. This behaves like :c:func:`PyModule_FromDefAndSpec2` + with *module_api_version* set to :const:`PYTHON_API_VERSION`. + + .. versionadded:: 3.5 + +.. c:function:: PyObject * PyModule_FromDefAndSpec2(PyModuleDef *def, PyObject *spec, int module_api_version) + + Create a new module object, given the definition in *module* and the + ModuleSpec *spec*, assuming the API version *module_api_version*. + If that version does not match the version of the running interpreter, + a :exc:`RuntimeWarning` is emitted. + + .. note:: + + Most uses of this function should be using :c:func:`PyModule_FromDefAndSpec` + instead; only use this if you are sure you need it. + + .. versionadded:: 3.5 + +.. c:function:: int PyModule_ExecDef(PyObject *module, PyModuleDef *def) + + Process any execution slots (:c:data:`Py_mod_exec`) given in *def*. + + .. versionadded:: 3.5 .. c:function:: int PyModule_SetDocString(PyObject *module, const char *docstring) - Set the docstring for *module* to *docstring*. Return ``-1`` on error, ``0`` - on success. + Set the docstring for *module* to *docstring*. + This function is called automatically when creating a module from + ``PyModuleDef``, using either ``PyModule_Create`` or + ``PyModule_FromDefAndSpec``. + + .. versionadded:: 3.5 .. c:function:: int PyModule_AddFunctions(PyObject *module, PyMethodDef *functions) - Add the functions from the ``NULL`` terminated *functions* array to *module*. + Add the functions from the *NULL* terminated *functions* array to *module*. Refer to the :c:type:`PyMethodDef` documentation for details on individual entries (due to the lack of a shared module namespace, module level "functions" implemented in C typically receive the module as their first parameter, making them similar to instance methods on Python classes). + This function is called automatically when creating a module from + ``PyModuleDef``, using either ``PyModule_Create`` or + ``PyModule_FromDefAndSpec``. + .. versionadded:: 3.5 + +Support functions +................. + +The module initialization function (if using single phase initialization) or +a function called from a module execution slot (if using multi-phase +initialization), can use the following functions to help initialize the module +state: .. c:function:: int PyModule_AddObject(PyObject *module, const char *name, PyObject *value) @@ -288,7 +421,7 @@ Add a string constant to *module* as *name*. This convenience function can be used from the module's initialization function. The string *value* must be - null-terminated. Return ``-1`` on error, ``0`` on success. + *NULL*-terminated. Return ``-1`` on error, ``0`` on success. .. c:function:: int PyModule_AddIntMacro(PyObject *module, macro) @@ -302,3 +435,36 @@ .. c:function:: int PyModule_AddStringMacro(PyObject *module, macro) Add a string constant to *module*. + + +Module lookup +^^^^^^^^^^^^^ + +Single-phase initialization creates singleton modules that can be looked up +in the context of the current interpreter. This allows the module object to be +retrieved later with only a reference to the module definition. + +These functions will not work on modules created using multi-phase initialization, +since multiple such modules can be created from a single definition. + +.. c:function:: PyObject* PyState_FindModule(PyModuleDef *def) + + Returns the module object that was created from *def* for the current interpreter. + This method requires that the module object has been attached to the interpreter state with + :c:func:`PyState_AddModule` beforehand. In case the corresponding module object is not + found or has not been attached to the interpreter state yet, it returns *NULL*. + +.. c:function:: int PyState_AddModule(PyObject *module, PyModuleDef *def) + + Attaches the module object passed to the function to the interpreter state. This allows + the module object to be accessible via :c:func:`PyState_FindModule`. + + Only effective on modules created using single-phase initialization. + + .. versionadded:: 3.3 + +.. c:function:: int PyState_RemoveModule(PyModuleDef *def) + + Removes the module object created from *def* from the interpreter state. + + .. versionadded:: 3.3 diff --git a/Doc/extending/building.rst b/Doc/extending/building.rst --- a/Doc/extending/building.rst +++ b/Doc/extending/building.rst @@ -1,27 +1,58 @@ .. highlightlang:: c - .. _building: -******************************************** +***************************** +Building C and C++ Extensions +***************************** + +A C extension for CPython is a shared library (e.g. a ``.so`` file on Linux, +``.pyd`` on Windows), which exports an *initialization function*. + +To be importable, the shared library must be available on :envvar:`PYTHONPATH`, +and must be named after the module name, with an appropriate extension. +When using distutils, the correct filename is generated automatically. + +The initialization function has the signature: + +.. c:function:: PyObject* PyInit_modulename(void) + +It returns either a fully-initialized module, or a :c:type:`PyModuleDef` +instance. See :ref:`initializing-modules` for details. + +.. highlightlang:: python + +For modules with ASCII-only names, the function must be named +``PyInit_``, with ```` replaced by the name of the +module. When using :ref:`multi-phase-initialization`, non-ASCII module names +are allowed. In this case, the initialization function name is +``PyInitU_``, with ```` encoded using Python's +*punycode* encoding with hyphens replaced by underscores. In Python:: + + def initfunc_name(name): + try: + suffix = b'_' + name.encode('ascii') + except UnicodeEncodeError: + suffix = b'U_' + name.encode('punycode').replace(b'-', b'_') + return b'PyInit' + suffix + +It is possible to export multiple modules from a single shared library by +defining multiple initialization functions. However, importing them requires +using symbolic links or a custom importer, because by default only the +function corresponding to the filename is found. +See :PEP:`489#multiple-modules-in-one-library` for details. + + +.. highlightlang:: c + Building C and C++ Extensions with distutils -******************************************** +============================================ .. sectionauthor:: Martin v. L?wis - -Starting in Python 1.4, Python provides, on Unix, a special make file for -building make files for building dynamically-linked extensions and custom -interpreters. Starting with Python 2.0, this mechanism (known as related to -Makefile.pre.in, and Setup files) is no longer supported. Building custom -interpreters was rarely used, and extension modules can be built using -distutils. - -Building an extension module using distutils requires that distutils is -installed on the build machine, which is included in Python 2.x and available -separately for Python 1.5. Since distutils also supports creation of binary -packages, users don't necessarily need a compiler and distutils to install the -extension. +Extension modules can be built using distutils, which is included in Python. +Since distutils also supports creation of binary packages, users don't +necessarily need a compiler and distutils to install the extension. A distutils package contains a driver script, :file:`setup.py`. This is a plain Python file, which, in the most simple case, could look like this:: diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -413,6 +413,13 @@ as :file:`Modules/xxmodule.c`. This file may be used as a template or simply read as an example. +.. note:: + + Unlike our ``spam`` example, ``xxmodule`` uses *multi-phase initialization* + (new in Python 3.5), where a PyModuleDef structure is returned from + ``PyInit_spam``, and creation of the module is left to the import machinery. + For details on multi-phase initialization, see :PEP:`489`. + .. _compilation: diff --git a/Doc/extending/windows.rst b/Doc/extending/windows.rst --- a/Doc/extending/windows.rst +++ b/Doc/extending/windows.rst @@ -98,9 +98,8 @@ it. Copy your C sources into it. Note that the module source file name does not necessarily have to match the module name, but the name of the initialization function should match the module name --- you can only import a - module :mod:`spam` if its initialization function is called :c:func:`initspam`, - and it should call :c:func:`Py_InitModule` with the string ``"spam"`` as its - first argument (use the minimal :file:`example.c` in this directory as a guide). + module :mod:`spam` if its initialization function is called :c:func:`PyInit_spam`, + (see :ref:`building`, or use the minimal :file:`Modules/xxmodule.c` as a guide). By convention, it lives in a file called :file:`spam.c` or :file:`spammodule.c`. The output file should be called :file:`spam.pyd` (in Release mode) or :file:`spam_d.pyd` (in Debug mode). The extension :file:`.pyd` was chosen diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -283,7 +283,7 @@ This change brings the import semantics of extension modules that opt-in to using the new mechanism much closer to those of Python source and bytecode -modules, including the ability to any valid identifier as a module name, +modules, including the ability to use any valid identifier as a module name, rather than being restricted to ASCII. .. seealso:: @@ -763,7 +763,7 @@ ----------- * The :mod:`unicodedata` module now uses data from `Unicode 8.0.0 -`_. + `_. wsgiref diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,9 @@ Documentation ------------- +- Issue #24458: Update documentation to cover multi-phase initialization for + extension modules (PEP 489). Patch by Petr Viktorin. + - Issue #24351: Clarify what is meant by "identifier" in the context of string.Template instances. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 15:31:30 2015 From: python-checkins at python.org (stefan.krah) Date: Fri, 03 Jul 2015 13:31:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0NTQz?= =?utf-8?q?=3A_Use_AC=5FLINK_instead_of_AC=5FCOMPILE_in_order_to_prevent_f?= =?utf-8?q?alse?= Message-ID: <20150703133130.11325.54868@psf.io> https://hg.python.org/cpython/rev/2a3c0ad52b99 changeset: 96778:2a3c0ad52b99 branch: 2.7 parent: 96753:301d7efac3de user: Stefan Krah date: Fri Jul 03 15:30:54 2015 +0200 summary: Issue #24543: Use AC_LINK instead of AC_COMPILE in order to prevent false positives with the -flto option (gcc >= 4.9.0 and clang). files: configure | 5 +++-- configure.ac | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -12747,12 +12747,13 @@ return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : have_gcc_asm_for_x87=yes else have_gcc_asm_for_x87=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x87" >&5 $as_echo "$have_gcc_asm_for_x87" >&6; } if test "$have_gcc_asm_for_x87" = yes diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -3723,7 +3723,7 @@ # so we try it on all platforms. AC_MSG_CHECKING(whether we can use gcc inline assembler to get and set x87 control word) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ unsigned short cw; __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 19:12:00 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 17:12:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41IChJc3N1ZSAjMjQ0MDAp?= Message-ID: <20150703171159.86787.68666@psf.io> https://hg.python.org/cpython/rev/a14f6a70d013 changeset: 96780:a14f6a70d013 parent: 96777:86daa37c1cc9 parent: 96779:cb1aafc9ad7e user: Yury Selivanov date: Fri Jul 03 13:11:54 2015 -0400 summary: Merge 3.5 (Issue #24400) files: Doc/library/collections.abc.rst | 18 +++++++++------- Doc/library/inspect.rst | 19 +++++++++++++++++ Doc/whatsnew/3.5.rst | 5 ++- Lib/_collections_abc.py | 17 +-------------- Lib/inspect.py | 7 ++++++ Lib/test/test_collections.py | 12 +++++++--- Lib/test/test_inspect.py | 23 +++++++++++++++++++++ Lib/test/test_types.py | 16 +++++++++++-- Lib/types.py | 10 ++++---- Misc/NEWS | 4 ++- 10 files changed, 92 insertions(+), 39 deletions(-) diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -162,10 +162,11 @@ :class:`~collections.abc.Coroutine` ABC are all instances of this ABC. .. note:: - In CPython, generator-based coroutines are *awaitables*, even though - they do not have an :meth:`__await__` method. This ABC - implements an :meth:`~class.__instancecheck__` method to make them - instances of itself. + In CPython, generator-based coroutines (generators decorated with + :func:`types.coroutine` or :func:`asyncio.coroutine`) are + *awaitables*, even though they do not have an :meth:`__await__` method. + Using ``isinstance(gencoro, Awaitable)`` for them will return ``False``. + Use :func:`inspect.isawaitable` to detect them. .. versionadded:: 3.5 @@ -179,10 +180,11 @@ :class:`Awaitable`. See also the definition of :term:`coroutine`. .. note:: - In CPython, generator-based coroutines are *awaitables* and *coroutines*, - even though they do not have an :meth:`__await__` method. This ABC - implements an :meth:`~class.__instancecheck__` method to make them - instances of itself. + In CPython, generator-based coroutines (generators decorated with + :func:`types.coroutine` or :func:`asyncio.coroutine`) are + *awaitables*, even though they do not have an :meth:`__await__` method. + Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``. + Use :func:`inspect.isawaitable` to detect them. .. versionadded:: 3.5 diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -310,6 +310,25 @@ .. versionadded:: 3.5 +.. function:: isawaitable(object) + + Return true if the object can be used in :keyword:`await` expression. + + Can also be used to distinguish generator-based coroutines from regular + generators:: + + def gen(): + yield + @types.coroutine + def gen_coro(): + yield + + assert not isawaitable(gen()) + assert isawaitable(gen_coro()) + + .. versionadded:: 3.5 + + .. function:: istraceback(object) Return true if the object is a traceback. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -532,8 +532,9 @@ * New argument ``follow_wrapped`` for :func:`inspect.signature`. (Contributed by Yury Selivanov in :issue:`20691`.) -* New :func:`~inspect.iscoroutine` and :func:`~inspect.iscoroutinefunction` - functions. (Contributed by Yury Selivanov in :issue:`24017`.) +* New :func:`~inspect.iscoroutine`, :func:`~inspect.iscoroutinefunction` + and :func:`~inspect.isawaitable` functions. (Contributed by + Yury Selivanov in :issue:`24017`.) * New :func:`~inspect.getcoroutinelocals` and :func:`~inspect.getcoroutinestate` functions. (Contributed by Yury Selivanov in :issue:`24400`.) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -81,22 +81,7 @@ return NotImplemented -class _AwaitableMeta(ABCMeta): - - def __instancecheck__(cls, instance): - # This hook is needed because we can't add - # '__await__' method to generator objects, and - # we can't register GeneratorType on Awaitable. - # NB: 0x100 = CO_ITERABLE_COROUTINE - # (We don't want to import 'inspect' module, as - # a dependency for 'collections.abc') - if (instance.__class__ is generator and - instance.gi_code.co_flags & 0x100): - return True - return super().__instancecheck__(instance) - - -class Awaitable(metaclass=_AwaitableMeta): +class Awaitable(metaclass=ABCMeta): __slots__ = () diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -207,6 +207,13 @@ """Return true if the object is a coroutine.""" return isinstance(object, types.CoroutineType) +def isawaitable(object): + """Return true is object can be passed to an ``await`` expression.""" + return (isinstance(object, types.CoroutineType) or + isinstance(object, types.GeneratorType) and + object.gi_code.co_flags & CO_ITERABLE_COROUTINE or + isinstance(object, collections.abc.Awaitable)) + def istraceback(object): """Return true if the object is a traceback. diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -511,8 +511,10 @@ self.assertTrue(issubclass(type(x), Awaitable)) c = coro() - self.assertIsInstance(c, Awaitable) - c.close() # awoid RuntimeWarning that coro() was not awaited + # Iterable coroutines (generators with CO_ITERABLE_COROUTINE + # flag don't have '__await__' method, hence can't be instances + # of Awaitable. Use inspect.isawaitable to detect them. + self.assertNotIsInstance(c, Awaitable) c = new_coro() self.assertIsInstance(c, Awaitable) @@ -559,8 +561,10 @@ self.assertTrue(issubclass(type(x), Awaitable)) c = coro() - self.assertIsInstance(c, Coroutine) - c.close() # awoid RuntimeWarning that coro() was not awaited + # Iterable coroutines (generators with CO_ITERABLE_COROUTINE + # flag don't have '__await__' method, hence can't be instances + # of Coroutine. Use inspect.isawaitable to detect them. + self.assertNotIsInstance(c, Coroutine) c = new_coro() self.assertIsInstance(c, Coroutine) 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 @@ -151,6 +151,29 @@ coro.close(); gen_coro.close() # silence warnings + def test_isawaitable(self): + def gen(): yield + self.assertFalse(inspect.isawaitable(gen())) + + coro = coroutine_function_example(1) + gen_coro = gen_coroutine_function_example(1) + + self.assertTrue(inspect.isawaitable(coro)) + self.assertTrue(inspect.isawaitable(gen_coro)) + + class Future: + def __await__(): + pass + self.assertTrue(inspect.isawaitable(Future())) + self.assertFalse(inspect.isawaitable(Future)) + + class NotFuture: pass + not_fut = NotFuture() + not_fut.__await__ = lambda: None + self.assertFalse(inspect.isawaitable(not_fut)) + + coro.close(); gen_coro.close() # silence warnings + def test_isroutine(self): self.assertTrue(inspect.isroutine(mod.spam)) self.assertTrue(inspect.isroutine([].count)) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -1447,6 +1447,19 @@ with self.assertRaisesRegex(Exception, 'ham'): wrapper.throw(Exception, Exception('ham')) + def test_returning_itercoro(self): + @types.coroutine + def gen(): + yield + + gencoro = gen() + + @types.coroutine + def foo(): + return gencoro + + self.assertIs(foo(), gencoro) + def test_genfunc(self): def gen(): yield self.assertIs(types.coroutine(gen), gen) @@ -1457,9 +1470,6 @@ g = gen() self.assertTrue(g.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE) self.assertFalse(g.gi_code.co_flags & inspect.CO_COROUTINE) - self.assertIsInstance(g, collections.abc.Coroutine) - self.assertIsInstance(g, collections.abc.Awaitable) - g.close() # silence warning self.assertIs(types.coroutine(gen), gen) diff --git a/Lib/types.py b/Lib/types.py --- a/Lib/types.py +++ b/Lib/types.py @@ -241,12 +241,12 @@ @_functools.wraps(func) def wrapped(*args, **kwargs): coro = func(*args, **kwargs) - if coro.__class__ is CoroutineType: - # 'coro' is a native coroutine object. + if (coro.__class__ is CoroutineType or + coro.__class__ is GeneratorType and coro.gi_code.co_flags & 0x100): + # 'coro' is a native coroutine object or an iterable coroutine return coro - if (coro.__class__ is GeneratorType or - (isinstance(coro, _collections_abc.Generator) and - not isinstance(coro, _collections_abc.Coroutine))): + if (isinstance(coro, _collections_abc.Generator) and + not isinstance(coro, _collections_abc.Coroutine)): # 'coro' is either a pure Python generator iterator, or it # implements collections.abc.Generator (and does not implement # collections.abc.Coroutine). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -41,7 +41,9 @@ uses collections.abc.Coroutine, it's intended to test for pure 'async def' coroutines only; add new opcode: GET_YIELD_FROM_ITER; fix generators wrapper used in types.coroutine to be instance of collections.abc.Generator; - inspect.isawaitable was removed (use collections.abc.Awaitable). + collections.abc.Awaitable and collections.abc.Coroutine can no longer + be used to detect generator-based coroutines--use inspect.isawaitable + instead. - Issue #24450: Add gi_yieldfrom to generators and cr_await to coroutines. Contributed by Benno Leslie and Yury Selivanov. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 19:11:59 2015 From: python-checkins at python.org (yury.selivanov) Date: Fri, 03 Jul 2015 17:11:59 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NDAw?= =?utf-8?q?=3A_Resurrect_inspect=2Eisawaitable=28=29?= Message-ID: <20150703171159.23315.29860@psf.io> https://hg.python.org/cpython/rev/cb1aafc9ad7e changeset: 96779:cb1aafc9ad7e branch: 3.5 parent: 96776:bad92d696866 user: Yury Selivanov date: Fri Jul 03 13:11:35 2015 -0400 summary: Issue #24400: Resurrect inspect.isawaitable() collections.abc.Awaitable and collections.abc.Coroutine no longer use __instancecheck__ hook to detect generator-based coroutines. inspect.isawaitable() can be used to detect generator-based coroutines and to distinguish them from regular generator objects. files: Doc/library/collections.abc.rst | 18 +++++++++------- Doc/library/inspect.rst | 19 +++++++++++++++++ Doc/whatsnew/3.5.rst | 5 ++- Lib/_collections_abc.py | 17 +-------------- Lib/inspect.py | 7 ++++++ Lib/test/test_collections.py | 12 +++++++--- Lib/test/test_inspect.py | 23 +++++++++++++++++++++ Lib/test/test_types.py | 16 +++++++++++-- Lib/types.py | 10 ++++---- Misc/NEWS | 4 ++- 10 files changed, 92 insertions(+), 39 deletions(-) diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -162,10 +162,11 @@ :class:`~collections.abc.Coroutine` ABC are all instances of this ABC. .. note:: - In CPython, generator-based coroutines are *awaitables*, even though - they do not have an :meth:`__await__` method. This ABC - implements an :meth:`~class.__instancecheck__` method to make them - instances of itself. + In CPython, generator-based coroutines (generators decorated with + :func:`types.coroutine` or :func:`asyncio.coroutine`) are + *awaitables*, even though they do not have an :meth:`__await__` method. + Using ``isinstance(gencoro, Awaitable)`` for them will return ``False``. + Use :func:`inspect.isawaitable` to detect them. .. versionadded:: 3.5 @@ -179,10 +180,11 @@ :class:`Awaitable`. See also the definition of :term:`coroutine`. .. note:: - In CPython, generator-based coroutines are *awaitables* and *coroutines*, - even though they do not have an :meth:`__await__` method. This ABC - implements an :meth:`~class.__instancecheck__` method to make them - instances of itself. + In CPython, generator-based coroutines (generators decorated with + :func:`types.coroutine` or :func:`asyncio.coroutine`) are + *awaitables*, even though they do not have an :meth:`__await__` method. + Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``. + Use :func:`inspect.isawaitable` to detect them. .. versionadded:: 3.5 diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -310,6 +310,25 @@ .. versionadded:: 3.5 +.. function:: isawaitable(object) + + Return true if the object can be used in :keyword:`await` expression. + + Can also be used to distinguish generator-based coroutines from regular + generators:: + + def gen(): + yield + @types.coroutine + def gen_coro(): + yield + + assert not isawaitable(gen()) + assert isawaitable(gen_coro()) + + .. versionadded:: 3.5 + + .. function:: istraceback(object) Return true if the object is a traceback. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -532,8 +532,9 @@ * New argument ``follow_wrapped`` for :func:`inspect.signature`. (Contributed by Yury Selivanov in :issue:`20691`.) -* New :func:`~inspect.iscoroutine` and :func:`~inspect.iscoroutinefunction` - functions. (Contributed by Yury Selivanov in :issue:`24017`.) +* New :func:`~inspect.iscoroutine`, :func:`~inspect.iscoroutinefunction` + and :func:`~inspect.isawaitable` functions. (Contributed by + Yury Selivanov in :issue:`24017`.) * New :func:`~inspect.getcoroutinelocals` and :func:`~inspect.getcoroutinestate` functions. (Contributed by Yury Selivanov in :issue:`24400`.) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -81,22 +81,7 @@ return NotImplemented -class _AwaitableMeta(ABCMeta): - - def __instancecheck__(cls, instance): - # This hook is needed because we can't add - # '__await__' method to generator objects, and - # we can't register GeneratorType on Awaitable. - # NB: 0x100 = CO_ITERABLE_COROUTINE - # (We don't want to import 'inspect' module, as - # a dependency for 'collections.abc') - if (instance.__class__ is generator and - instance.gi_code.co_flags & 0x100): - return True - return super().__instancecheck__(instance) - - -class Awaitable(metaclass=_AwaitableMeta): +class Awaitable(metaclass=ABCMeta): __slots__ = () diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -207,6 +207,13 @@ """Return true if the object is a coroutine.""" return isinstance(object, types.CoroutineType) +def isawaitable(object): + """Return true is object can be passed to an ``await`` expression.""" + return (isinstance(object, types.CoroutineType) or + isinstance(object, types.GeneratorType) and + object.gi_code.co_flags & CO_ITERABLE_COROUTINE or + isinstance(object, collections.abc.Awaitable)) + def istraceback(object): """Return true if the object is a traceback. diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -511,8 +511,10 @@ self.assertTrue(issubclass(type(x), Awaitable)) c = coro() - self.assertIsInstance(c, Awaitable) - c.close() # awoid RuntimeWarning that coro() was not awaited + # Iterable coroutines (generators with CO_ITERABLE_COROUTINE + # flag don't have '__await__' method, hence can't be instances + # of Awaitable. Use inspect.isawaitable to detect them. + self.assertNotIsInstance(c, Awaitable) c = new_coro() self.assertIsInstance(c, Awaitable) @@ -559,8 +561,10 @@ self.assertTrue(issubclass(type(x), Awaitable)) c = coro() - self.assertIsInstance(c, Coroutine) - c.close() # awoid RuntimeWarning that coro() was not awaited + # Iterable coroutines (generators with CO_ITERABLE_COROUTINE + # flag don't have '__await__' method, hence can't be instances + # of Coroutine. Use inspect.isawaitable to detect them. + self.assertNotIsInstance(c, Coroutine) c = new_coro() self.assertIsInstance(c, Coroutine) 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 @@ -151,6 +151,29 @@ coro.close(); gen_coro.close() # silence warnings + def test_isawaitable(self): + def gen(): yield + self.assertFalse(inspect.isawaitable(gen())) + + coro = coroutine_function_example(1) + gen_coro = gen_coroutine_function_example(1) + + self.assertTrue(inspect.isawaitable(coro)) + self.assertTrue(inspect.isawaitable(gen_coro)) + + class Future: + def __await__(): + pass + self.assertTrue(inspect.isawaitable(Future())) + self.assertFalse(inspect.isawaitable(Future)) + + class NotFuture: pass + not_fut = NotFuture() + not_fut.__await__ = lambda: None + self.assertFalse(inspect.isawaitable(not_fut)) + + coro.close(); gen_coro.close() # silence warnings + def test_isroutine(self): self.assertTrue(inspect.isroutine(mod.spam)) self.assertTrue(inspect.isroutine([].count)) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -1447,6 +1447,19 @@ with self.assertRaisesRegex(Exception, 'ham'): wrapper.throw(Exception, Exception('ham')) + def test_returning_itercoro(self): + @types.coroutine + def gen(): + yield + + gencoro = gen() + + @types.coroutine + def foo(): + return gencoro + + self.assertIs(foo(), gencoro) + def test_genfunc(self): def gen(): yield self.assertIs(types.coroutine(gen), gen) @@ -1457,9 +1470,6 @@ g = gen() self.assertTrue(g.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE) self.assertFalse(g.gi_code.co_flags & inspect.CO_COROUTINE) - self.assertIsInstance(g, collections.abc.Coroutine) - self.assertIsInstance(g, collections.abc.Awaitable) - g.close() # silence warning self.assertIs(types.coroutine(gen), gen) diff --git a/Lib/types.py b/Lib/types.py --- a/Lib/types.py +++ b/Lib/types.py @@ -241,12 +241,12 @@ @_functools.wraps(func) def wrapped(*args, **kwargs): coro = func(*args, **kwargs) - if coro.__class__ is CoroutineType: - # 'coro' is a native coroutine object. + if (coro.__class__ is CoroutineType or + coro.__class__ is GeneratorType and coro.gi_code.co_flags & 0x100): + # 'coro' is a native coroutine object or an iterable coroutine return coro - if (coro.__class__ is GeneratorType or - (isinstance(coro, _collections_abc.Generator) and - not isinstance(coro, _collections_abc.Coroutine))): + if (isinstance(coro, _collections_abc.Generator) and + not isinstance(coro, _collections_abc.Coroutine)): # 'coro' is either a pure Python generator iterator, or it # implements collections.abc.Generator (and does not implement # collections.abc.Coroutine). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,7 +25,9 @@ uses collections.abc.Coroutine, it's intended to test for pure 'async def' coroutines only; add new opcode: GET_YIELD_FROM_ITER; fix generators wrapper used in types.coroutine to be instance of collections.abc.Generator; - inspect.isawaitable was removed (use collections.abc.Awaitable). + collections.abc.Awaitable and collections.abc.Coroutine can no longer + be used to detect generator-based coroutines--use inspect.isawaitable + instead. - Issue #24450: Add gi_yieldfrom to generators and cr_await to coroutines. Contributed by Benno Leslie and Yury Selivanov. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 21:21:47 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 03 Jul 2015 19:21:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Fixes_warnings_when_building_python3=2Edll_due_to_the_?= =?utf-8?q?=2Edef_file_accumulating?= Message-ID: <20150703192147.21360.37016@psf.io> https://hg.python.org/cpython/rev/e5082ddfbb60 changeset: 96782:e5082ddfbb60 parent: 96780:a14f6a70d013 parent: 96781:1d0ec12b1e03 user: Steve Dower date: Fri Jul 03 12:21:29 2015 -0700 summary: Fixes warnings when building python3.dll due to the .def file accumulating multiple copies of each line. Adds shebang line to prepare_ssl so it will run with py.exe. files: PCbuild/prepare_ssl.py | 1 + PCbuild/python3dll.vcxproj | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/PCbuild/prepare_ssl.py b/PCbuild/prepare_ssl.py --- a/PCbuild/prepare_ssl.py +++ b/PCbuild/prepare_ssl.py @@ -1,3 +1,4 @@ +#! /usr/bin/env python3 # Script for preparing OpenSSL for building on Windows. # Uses Perl to create nmake makefiles and otherwise prepare the way # for building on 32 or 64 bit platforms. diff --git a/PCbuild/python3dll.vcxproj b/PCbuild/python3dll.vcxproj --- a/PCbuild/python3dll.vcxproj +++ b/PCbuild/python3dll.vcxproj @@ -109,7 +109,7 @@ - + @@ -132,7 +132,7 @@ <_Lines Include="@(_Symbols->'%(Symbol)')" /> - + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Jul 3 21:21:47 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 03 Jul 2015 19:21:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Fixes_warnings?= =?utf-8?q?_when_building_python3=2Edll_due_to_the_=2Edef_file_accumulatin?= =?utf-8?q?g?= Message-ID: <20150703192147.20885.15326@psf.io> https://hg.python.org/cpython/rev/1d0ec12b1e03 changeset: 96781:1d0ec12b1e03 branch: 3.5 parent: 96779:cb1aafc9ad7e user: Steve Dower date: Fri Jul 03 09:08:47 2015 -0700 summary: Fixes warnings when building python3.dll due to the .def file accumulating multiple copies of each line. Adds shebang line to prepare_ssl so it will run with py.exe. files: PCbuild/prepare_ssl.py | 1 + PCbuild/python3dll.vcxproj | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/PCbuild/prepare_ssl.py b/PCbuild/prepare_ssl.py --- a/PCbuild/prepare_ssl.py +++ b/PCbuild/prepare_ssl.py @@ -1,3 +1,4 @@ +#! /usr/bin/env python3 # Script for preparing OpenSSL for building on Windows. # Uses Perl to create nmake makefiles and otherwise prepare the way # for building on 32 or 64 bit platforms. diff --git a/PCbuild/python3dll.vcxproj b/PCbuild/python3dll.vcxproj --- a/PCbuild/python3dll.vcxproj +++ b/PCbuild/python3dll.vcxproj @@ -109,7 +109,7 @@ - + @@ -132,7 +132,7 @@ <_Lines Include="@(_Symbols->'%(Symbol)')" /> - + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 00:17:58 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 03 Jul 2015 22:17:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI0NDMy?= =?utf-8?q?=3A_Update_Windows_builds_to_use_OpenSSL_1=2E0=2E2c=2E?= Message-ID: <20150703221758.10428.71942@psf.io> https://hg.python.org/cpython/rev/6fd63f0a0026 changeset: 96783:6fd63f0a0026 branch: 3.4 parent: 96769:34460219c0e0 user: Steve Dower date: Fri Jul 03 15:13:48 2015 -0700 summary: Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. files: Misc/NEWS | 2 ++ PCbuild/get_externals.bat | 2 +- PCbuild/pyproject.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -343,6 +343,8 @@ - Issue #23686: Update OS X 10.5 installer and Windows builds to use OpenSSL 1.0.2a. +- Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. + C API ----- diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ for %%e in ( bzip2-1.0.6 nasm-2.11.06 - openssl-1.0.2a + openssl-1.0.2c tcl-8.6.1.0 tk-8.6.1.0 tix-8.4.3.4 diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -20,7 +20,7 @@ $(externalsDir)\sqlite-3.8.3.1 $(externalsDir)\bzip2-1.0.6 $(externalsDir)\xz-5.0.5 - $(externalsDir)\openssl-1.0.2a + $(externalsDir)\openssl-1.0.2c $(externalsDir)\tcltk $(externalsDir)\tcltk64 $(tcltkDir)\lib\tcl86t.lib;$(tcltkDir)\lib\tk86t.lib diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -171,7 +171,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.2a of the OpenSSL secure sockets + Python wrapper for version 1.0.2c of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 00:17:58 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 03 Jul 2015 22:17:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Issue_=2324432=3A_Update_Windows_builds_to_use_OpenSSL_1=2E0?= =?utf-8?q?=2E2c=2E?= Message-ID: <20150703221758.24661.71566@psf.io> https://hg.python.org/cpython/rev/ebc8559b2e57 changeset: 96784:ebc8559b2e57 branch: 3.5 parent: 96781:1d0ec12b1e03 parent: 96783:6fd63f0a0026 user: Steve Dower date: Fri Jul 03 15:16:37 2015 -0700 summary: Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. files: Misc/NEWS | 5 +++++ PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -100,6 +100,11 @@ - Issue #24351: Clarify what is meant by "identifier" in the context of string.Template instances. +Build +----- + +- Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. + What's New in Python 3.5.0 beta 2? ================================== diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ for %%e in ( bzip2-1.0.6 nasm-2.11.06 - openssl-1.0.2a + openssl-1.0.2c tcl-core-8.6.4.1 tk-8.6.4.1 tix-8.4.3.4 diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -34,7 +34,7 @@ $(ExternalsDir)sqlite-3.8.3.1\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.0.5\ - $(ExternalsDir)openssl-1.0.2a\ + $(ExternalsDir)openssl-1.0.2c\ $(ExternalsDir)\nasm-2.11.06\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -197,7 +197,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.1j of the OpenSSL secure sockets + Python wrapper for version 1.0.2c of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 00:17:58 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 03 Jul 2015 22:17:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2324432=3A_Update_Windows_builds_to_use_OpenSSL_1?= =?utf-8?b?LjAuMmMu?= Message-ID: <20150703221758.30594.7072@psf.io> https://hg.python.org/cpython/rev/91c5097bca2b changeset: 96785:91c5097bca2b parent: 96782:e5082ddfbb60 parent: 96784:ebc8559b2e57 user: Steve Dower date: Fri Jul 03 15:17:17 2015 -0700 summary: Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. files: Misc/NEWS | 5 +++++ PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -116,6 +116,11 @@ - Issue #24351: Clarify what is meant by "identifier" in the context of string.Template instances. +Build +----- + +- Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. + What's New in Python 3.5.0 beta 2? ================================== diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ for %%e in ( bzip2-1.0.6 nasm-2.11.06 - openssl-1.0.2a + openssl-1.0.2c tcl-core-8.6.4.1 tk-8.6.4.1 tix-8.4.3.4 diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -34,7 +34,7 @@ $(ExternalsDir)sqlite-3.8.3.1\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.0.5\ - $(ExternalsDir)openssl-1.0.2a\ + $(ExternalsDir)openssl-1.0.2c\ $(ExternalsDir)\nasm-2.11.06\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -197,7 +197,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.1j of the OpenSSL secure sockets + Python wrapper for version 1.0.2c of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 00:19:51 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 03 Jul 2015 22:19:51 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0NDMy?= =?utf-8?q?=3A_Update_Windows_builds_to_use_OpenSSL_1=2E0=2E2c=2E?= Message-ID: <20150703221951.736.51669@psf.io> https://hg.python.org/cpython/rev/c49d2ea5e48a changeset: 96786:c49d2ea5e48a branch: 2.7 parent: 96778:2a3c0ad52b99 user: Steve Dower date: Fri Jul 03 15:19:38 2015 -0700 summary: Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. files: Misc/NEWS | 6 ++++++ PCbuild/get_externals.bat | 2 +- PCbuild/pyproject.vsprops | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,12 @@ - Issue #24134: Reverted issue #24134 changes. +Build +----- + +- Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. + + IDLE ---- diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -55,7 +55,7 @@ bzip2-1.0.6 db-4.7.25.0 nasm-2.11.06 - openssl-1.0.2a + openssl-1.0.2c tcl-8.5.15.0 tk-8.5.15.0 tix-8.4.3.5 diff --git a/PCbuild/pyproject.vsprops b/PCbuild/pyproject.vsprops --- a/PCbuild/pyproject.vsprops +++ b/PCbuild/pyproject.vsprops @@ -82,7 +82,7 @@ /> https://hg.python.org/cpython/rev/25985b0c4dbf changeset: 96787:25985b0c4dbf branch: 2.7 user: Terry Jan Reedy date: Fri Jul 03 19:10:14 2015 -0400 summary: Issue #24525: Add missing word. Patch by Vincent Legoll. files: Doc/library/urllib.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/urllib.rst b/Doc/library/urllib.rst --- a/Doc/library/urllib.rst +++ b/Doc/library/urllib.rst @@ -296,7 +296,7 @@ .. note:: urllib also exposes certain utility functions like splittype, splithost and others parsing url into various components. But it is recommended to use - :mod:`urlparse` for parsing urls than using these functions directly. + :mod:`urlparse` for parsing urls rather than using these functions directly. Python 3 does not expose these helper functions from :mod:`urllib.parse` module. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 02:21:22 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 04 Jul 2015 00:21:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_insertion_resize_logi?= =?utf-8?b?YyBpbnRvIHNldF9pbnNlcnRfa2V5KCku?= Message-ID: <20150704002122.124440.41373@psf.io> https://hg.python.org/cpython/rev/1fa89f685c4b changeset: 96788:1fa89f685c4b parent: 96785:91c5097bca2b user: Raymond Hettinger date: Fri Jul 03 17:21:17 2015 -0700 summary: Move insertion resize logic into set_insert_key(). Simplifies the code a little bit and does the resize check only when a new key is added (giving a small speed up in the case where the key already exists). Fixes possible bug in set_merge() where the set_insert_key() call relies on a big resize at the start to make enough room for the keys but is vulnerable to a comparision callback that could cause the table to shrink in the middle of the merge. Also, changed the resize threshold from two-thirds of the mask+1 to just two-thirds. The plus one offset gave no real benefit (afterall, the two-thirds mark is just a heuristic and isn't a precise cut-off). files: Objects/setobject.c | 75 +++++++++++--------------------- 1 files changed, 27 insertions(+), 48 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -125,6 +125,8 @@ } } +static int set_table_resize(PySetObject *, Py_ssize_t); + static int set_insert_key(PySetObject *so, PyObject *key, Py_hash_t hash) { @@ -139,7 +141,7 @@ entry = &table[i]; if (entry->key == NULL) - goto found_null_first; + goto found_unused; freeslot = NULL; perturb = hash; @@ -173,7 +175,7 @@ for (j = 0 ; j < LINEAR_PROBES ; j++) { entry++; if (entry->hash == 0 && entry->key == NULL) - goto found_null; + goto found_unused_or_dummy; if (entry->hash == hash) { PyObject *startkey = entry->key; assert(startkey != dummy); @@ -204,30 +206,27 @@ entry = &table[i]; if (entry->key == NULL) - goto found_null; + goto found_unused_or_dummy; } - found_null_first: + found_unused_or_dummy: + if (freeslot == NULL) + goto found_unused; + Py_INCREF(key); + so->used++; + freeslot->key = key; + freeslot->hash = hash; + return 0; + + found_unused: Py_INCREF(key); so->fill++; so->used++; entry->key = key; entry->hash = hash; - return 0; - - found_null: - Py_INCREF(key); - if (freeslot == NULL) { - /* UNUSED */ - so->fill++; - } else { - /* DUMMY */ - entry = freeslot; - } - so->used++; - entry->key = key; - entry->hash = hash; - return 0; + if ((size_t)so->fill*3 < mask*2) + return 0; + return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); found_active: return 0; @@ -366,28 +365,15 @@ return 0; } -/* CAUTION: set_add_key/entry() must guarantee it won't resize the table */ - static int set_add_entry(PySetObject *so, setentry *entry) { - Py_ssize_t n_used; - PyObject *key = entry->key; - Py_hash_t hash = entry->hash; - - assert(so->fill <= so->mask); /* at least one empty slot */ - n_used = so->used; - if (set_insert_key(so, key, hash)) - return -1; - if (!(so->used > n_used && so->fill*3 >= (so->mask+1)*2)) - return 0; - return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); + return set_insert_key(so, entry->key, entry->hash); } static int set_add_key(PySetObject *so, PyObject *key) { - setentry entry; Py_hash_t hash; if (!PyUnicode_CheckExact(key) || @@ -396,9 +382,7 @@ if (hash == -1) return -1; } - entry.key = key; - entry.hash = hash; - return set_add_entry(so, &entry); + return set_insert_key(so, key, hash); } #define DISCARD_NOTFOUND 0 @@ -631,7 +615,7 @@ * incrementally resizing as we insert new keys. Expect * that there will be no (or few) overlapping keys. */ - if ((so->fill + other->used)*3 >= (so->mask+1)*2) { + if ((so->fill + other->used)*3 >= so->mask*2) { if (set_table_resize(so, (so->used + other->used)*2) != 0) return -1; } @@ -979,16 +963,12 @@ */ if (dictsize == -1) return -1; - if ((so->fill + dictsize)*3 >= (so->mask+1)*2) { + if ((so->fill + dictsize)*3 >= so->mask*2) { if (set_table_resize(so, (so->used + dictsize)*2) != 0) return -1; } while (_PyDict_Next(other, &pos, &key, &value, &hash)) { - setentry an_entry; - - an_entry.hash = hash; - an_entry.key = key; - if (set_add_entry(so, &an_entry)) + if (set_insert_key(so, key, hash)) return -1; } return 0; @@ -1583,17 +1563,16 @@ if (PyDict_CheckExact(other)) { while (set_next(so, &pos, &entry)) { - setentry entrycopy; + PyObject *key = entry->key; + Py_hash_t hash = entry->hash; int rv; - entrycopy.hash = entry->hash; - entrycopy.key = entry->key; - rv = _PyDict_Contains(other, entry->key, entry->hash); + rv = _PyDict_Contains(other, key, hash); if (rv < 0) { Py_DECREF(result); return NULL; } if (!rv) { - if (set_add_entry((PySetObject *)result, &entrycopy)) { + if (set_insert_key((PySetObject *)result, key, hash)) { Py_DECREF(result); return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 03:31:15 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 04 Jul 2015 01:31:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Call_set=5Flookkey=28=29_d?= =?utf-8?q?irectly_to_avoid_unnecessary_memory_spills_and_reloads=2E?= Message-ID: <20150704013115.17013.25590@psf.io> https://hg.python.org/cpython/rev/fa3ed4e75ccd changeset: 96789:fa3ed4e75ccd user: Raymond Hettinger date: Fri Jul 03 18:31:09 2015 -0700 summary: Call set_lookkey() directly to avoid unnecessary memory spills and reloads. files: Objects/setobject.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -678,7 +678,7 @@ static int set_contains_key(PySetObject *so, PyObject *key) { - setentry entry; + setentry *entry; Py_hash_t hash; if (!PyUnicode_CheckExact(key) || @@ -687,9 +687,10 @@ if (hash == -1) return -1; } - entry.key = key; - entry.hash = hash; - return set_contains_entry(so, &entry); + entry = set_lookkey(so, key, hash); + if (entry == NULL) + return -1; + return entry->key != NULL; } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 05:00:07 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 04 Jul 2015 03:00:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_factoring=3A__move_r?= =?utf-8?q?edundant_resize_scaling_logic_into_the_resize_function=2E?= Message-ID: <20150704030007.13199.52503@psf.io> https://hg.python.org/cpython/rev/596ca185e3dc changeset: 96790:596ca185e3dc user: Raymond Hettinger date: Fri Jul 03 20:00:03 2015 -0700 summary: Minor factoring: move redundant resize scaling logic into the resize function. files: Objects/setobject.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -226,7 +226,7 @@ entry->hash = hash; if ((size_t)so->fill*3 < mask*2) return 0; - return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); + return set_table_resize(so, so->used); found_active: return 0; @@ -290,6 +290,7 @@ setentry small_copy[PySet_MINSIZE]; assert(minused >= 0); + minused = (minused > 50000) ? minused * 2 : minused * 4; /* Find the smallest table size > minused. */ /* XXX speed-up with intrinsics */ @@ -616,7 +617,7 @@ * that there will be no (or few) overlapping keys. */ if ((so->fill + other->used)*3 >= so->mask*2) { - if (set_table_resize(so, (so->used + other->used)*2) != 0) + if (set_table_resize(so, so->used + other->used) != 0) return -1; } so_entry = so->table; @@ -965,7 +966,7 @@ if (dictsize == -1) return -1; if ((so->fill + dictsize)*3 >= so->mask*2) { - if (set_table_resize(so, (so->used + dictsize)*2) != 0) + if (set_table_resize(so, so->used + dictsize) != 0) return -1; } while (_PyDict_Next(other, &pos, &key, &value, &hash)) { @@ -1508,7 +1509,7 @@ /* If more than 1/5 are dummies, then resize them away. */ if ((so->fill - so->used) * 5 < so->mask) return 0; - return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); + return set_table_resize(so, so->used); } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 08:37:22 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 04 Jul 2015 06:37:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_nit=3A__Make_the_sty?= =?utf-8?q?le_of_checking_error_return_values_more_consistent=2E?= Message-ID: <20150704063722.87143.99275@psf.io> https://hg.python.org/cpython/rev/6c58b5b82505 changeset: 96791:6c58b5b82505 user: Raymond Hettinger date: Fri Jul 03 23:37:16 2015 -0700 summary: Minor nit: Make the style of checking error return values more consistent. files: Objects/setobject.c | 32 ++++++++++++++++---------------- 1 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1270,7 +1270,7 @@ while (set_next((PySetObject *)other, &pos, &entry)) { int rv = set_contains_entry(so, entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(result); return NULL; } @@ -1304,7 +1304,7 @@ entry.hash = hash; entry.key = key; rv = set_contains_entry(so, &entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(it); Py_DECREF(result); Py_DECREF(key); @@ -1431,7 +1431,7 @@ } while (set_next((PySetObject *)other, &pos, &entry)) { int rv = set_contains_entry(so, entry); - if (rv == -1) + if (rv < 0) return NULL; if (rv) Py_RETURN_FALSE; @@ -1486,7 +1486,7 @@ Py_ssize_t pos = 0; while (set_next((PySetObject *)other, &pos, &entry)) - if (set_discard_entry(so, entry) == -1) + if (set_discard_entry(so, entry) < 0) return -1; } else { PyObject *key, *it; @@ -1495,7 +1495,7 @@ return -1; while ((key = PyIter_Next(it)) != NULL) { - if (set_discard_key(so, key) == -1) { + if (set_discard_key(so, key) < 0) { Py_DECREF(it); Py_DECREF(key); return -1; @@ -1536,7 +1536,7 @@ result = set_copy(so); if (result == NULL) return NULL; - if (set_difference_update_internal((PySetObject *) result, other) != -1) + if (set_difference_update_internal((PySetObject *) result, other) == 0) return result; Py_DECREF(result); return NULL; @@ -1586,7 +1586,7 @@ /* Iterate over so, checking for common elements in other. */ while (set_next(so, &pos, &entry)) { int rv = set_contains_entry((PySetObject *)other, entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(result); return NULL; } @@ -1670,7 +1670,7 @@ an_entry.key = key; rv = set_discard_entry(so, &an_entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(key); return NULL; } @@ -1696,7 +1696,7 @@ while (set_next(otherset, &pos, &entry)) { int rv = set_discard_entry(so, entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(otherset); return NULL; } @@ -1778,7 +1778,7 @@ while (set_next(so, &pos, &entry)) { int rv = set_contains_entry((PySetObject *)other, entry); - if (rv == -1) + if (rv < 0) return NULL; if (!rv) Py_RETURN_FALSE; @@ -1869,7 +1869,7 @@ int rv; rv = set_contains_key(so, key); - if (rv == -1) { + if (rv < 0) { if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) return -1; PyErr_Clear(); @@ -1888,7 +1888,7 @@ long result; result = set_contains(so, key); - if (result == -1) + if (result < 0) return NULL; return PyBool_FromLong(result); } @@ -1902,7 +1902,7 @@ int rv; rv = set_discard_key(so, key); - if (rv == -1) { + if (rv < 0) { if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) return NULL; PyErr_Clear(); @@ -1911,7 +1911,7 @@ return NULL; rv = set_discard_key(so, tmpkey); Py_DECREF(tmpkey); - if (rv == -1) + if (rv < 0) return NULL; } @@ -1934,7 +1934,7 @@ int rv; rv = set_discard_key(so, key); - if (rv == -1) { + if (rv < 0) { if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) return NULL; PyErr_Clear(); @@ -1943,7 +1943,7 @@ return NULL; rv = set_discard_key(so, tmpkey); Py_DECREF(tmpkey); - if (rv == -1) + if (rv < 0) return NULL; } Py_RETURN_NONE; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 08:47:38 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 06:47:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI0NDMy?= =?utf-8?q?=3A_Update_OS_X_10=2E5+_installer_builds_to_use_OpenSSL_1=2E0?= =?utf-8?q?=2E2c=2E?= Message-ID: <20150704064738.17013.93329@psf.io> https://hg.python.org/cpython/rev/4b52fce3753d changeset: 96793:4b52fce3753d branch: 3.4 parent: 96783:6fd63f0a0026 user: Ned Deily date: Fri Jul 03 23:35:00 2015 -0700 summary: Issue #24432: Update OS X 10.5+ installer builds to use OpenSSL 1.0.2c. files: Mac/BuildScript/build-installer.py | 6 +++--- Mac/BuildScript/openssl_sdk_makedepend.patch | 2 +- Misc/NEWS | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2a", - url="https://www.openssl.org/source/openssl-1.0.2a.tar.gz", - checksum='a06c547dac9044161a477211049f60ef', + name="OpenSSL 1.0.2c", + url="https://www.openssl.org/source/openssl-1.0.2c.tar.gz", + checksum='8c8d81a9ae7005276e486702edbcd4b6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -2,7 +2,7 @@ # Parent 25a9af415e8c3faf591c360d5f0e361d049b2b43 # openssl_sdk_makedepend.patch # -# using openssl 1.0.2a +# using openssl 1.0.2c # # - support building with an OS X SDK # - allow "make depend" to use compilers with names other than "gcc" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -340,10 +340,8 @@ - Issue #23445: pydebug builds now use "gcc -Og" where possible, to make the resulting executable faster. -- Issue #23686: Update OS X 10.5 installer and Windows builds to use - OpenSSL 1.0.2a. - -- Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. +- Issue #24432: Update Windows builds and OS X 10.5 installer to use OpenSSL + 1.0.2c. C API ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 08:47:38 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 06:47:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0NDMy?= =?utf-8?q?=3A_Update_OS_X_10=2E5+_installer_builds_to_use_OpenSSL_1=2E0?= =?utf-8?q?=2E2c=2E?= Message-ID: <20150704064738.97844.13472@psf.io> https://hg.python.org/cpython/rev/695bbbaf2478 changeset: 96792:695bbbaf2478 branch: 2.7 parent: 96787:25985b0c4dbf user: Ned Deily date: Fri Jul 03 23:32:44 2015 -0700 summary: Issue #24432: Update OS X 10.5+ installer builds to use OpenSSL 1.0.2c. files: Mac/BuildScript/build-installer.py | 6 +++--- Mac/BuildScript/openssl_sdk_makedepend.patch | 2 +- Misc/NEWS | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2a", - url="https://www.openssl.org/source/openssl-1.0.2a.tar.gz", - checksum='a06c547dac9044161a477211049f60ef', + name="OpenSSL 1.0.2c", + url="https://www.openssl.org/source/openssl-1.0.2c.tar.gz", + checksum='8c8d81a9ae7005276e486702edbcd4b6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -2,7 +2,7 @@ # Parent 25a9af415e8c3faf591c360d5f0e361d049b2b43 # openssl_sdk_makedepend.patch # -# using openssl 1.0.2a +# using openssl 1.0.2c # # - support building with an OS X SDK # - allow "make depend" to use compilers with names other than "gcc" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -95,8 +95,8 @@ Build ----- -- Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. - +- Issue #24432: Update Windows builds and OS X 10.5 installer to use OpenSSL + 1.0.2c. IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 08:47:43 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 06:47:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Issue_=2324432=3A_Update_OS_X_10=2E5+_installer_builds_to_use_?= =?utf-8?b?T3BlblNTTCAxLjAuMmMu?= Message-ID: <20150704064743.63903.26828@psf.io> https://hg.python.org/cpython/rev/bbf4e35ed69e changeset: 96794:bbf4e35ed69e branch: 3.5 parent: 96784:ebc8559b2e57 parent: 96793:4b52fce3753d user: Ned Deily date: Fri Jul 03 23:43:22 2015 -0700 summary: Issue #24432: Update OS X 10.5+ installer builds to use OpenSSL 1.0.2c. files: Mac/BuildScript/build-installer.py | 6 +++--- Mac/BuildScript/openssl_sdk_makedepend.patch | 2 +- Misc/NEWS | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2a", - url="https://www.openssl.org/source/openssl-1.0.2a.tar.gz", - checksum='a06c547dac9044161a477211049f60ef', + name="OpenSSL 1.0.2c", + url="https://www.openssl.org/source/openssl-1.0.2c.tar.gz", + checksum='8c8d81a9ae7005276e486702edbcd4b6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -2,7 +2,7 @@ # Parent 25a9af415e8c3faf591c360d5f0e361d049b2b43 # openssl_sdk_makedepend.patch # -# using openssl 1.0.2a +# using openssl 1.0.2c # # - support building with an OS X SDK # - allow "make depend" to use compilers with names other than "gcc" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,7 +103,8 @@ Build ----- -- Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. +- Issue #24432: Update Windows builds and OS X 10.5 installer to use OpenSSL + 1.0.2c. What's New in Python 3.5.0 beta 2? -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 08:47:43 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 06:47:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2324432=3A_merge_from_3=2E5?= Message-ID: <20150704064743.15337.93840@psf.io> https://hg.python.org/cpython/rev/fbb9ac8aebfd changeset: 96795:fbb9ac8aebfd parent: 96791:6c58b5b82505 parent: 96794:bbf4e35ed69e user: Ned Deily date: Fri Jul 03 23:47:02 2015 -0700 summary: Issue #24432: merge from 3.5 files: Mac/BuildScript/build-installer.py | 6 +++--- Mac/BuildScript/openssl_sdk_makedepend.patch | 2 +- Misc/NEWS | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2a", - url="https://www.openssl.org/source/openssl-1.0.2a.tar.gz", - checksum='a06c547dac9044161a477211049f60ef', + name="OpenSSL 1.0.2c", + url="https://www.openssl.org/source/openssl-1.0.2c.tar.gz", + checksum='8c8d81a9ae7005276e486702edbcd4b6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -2,7 +2,7 @@ # Parent 25a9af415e8c3faf591c360d5f0e361d049b2b43 # openssl_sdk_makedepend.patch # -# using openssl 1.0.2a +# using openssl 1.0.2c # # - support building with an OS X SDK # - allow "make depend" to use compilers with names other than "gcc" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -119,7 +119,8 @@ Build ----- -- Issue #24432: Update Windows builds to use OpenSSL 1.0.2c. +- Issue #24432: Update Windows builds and OS X 10.5 installer to use OpenSSL + 1.0.2c. What's New in Python 3.5.0 beta 2? -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 08:55:59 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 06:55:59 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Updates_to_the_OS_X_installer_=28merge_from_3=2E5=29?= Message-ID: <20150704065559.15337.80058@psf.io> https://hg.python.org/cpython/rev/1d7496eff907 changeset: 96797:1d7496eff907 parent: 96795:fbb9ac8aebfd parent: 96796:212a436483d6 user: Ned Deily date: Fri Jul 03 23:55:23 2015 -0700 summary: Updates to the OS X installer (merge from 3.5) files: Mac/BuildScript/resources/ReadMe.rtf | 69 +++++++++- Mac/BuildScript/scripts/postflight.ensurepip | 10 +- Mac/BuildScript/scripts/postflight.framework | 16 +- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1347\cocoasubrtf570 +{\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} \margl1440\margr1440\vieww13380\viewh14600\viewkind0 @@ -24,7 +24,7 @@ \i0 variant. Unless you are installing to an 10.5 system or you need to build applications that can run on 10.5 systems, use the 10.6 variant if possible. There are some additional operating system functions that are supported starting with 10.6 and you may see better performance using 64-bit mode. By default, Python will automatically run in 64-bit mode if your system supports it. Also see \i Certificate verification and OpenSSL \i0 below. The Pythons installed by these installers are built with private copies of some third-party libraries not included with or newer than those in OS X itself. The list of these libraries varies by installer variant and is included at the end of the License.rtf file. -\b \ul \ulc0 \ +\b \ul \ \ Update your version of Tcl/Tk to use IDLE or other Tk applications \b0 \ulnone \ @@ -36,6 +36,71 @@ \i0 for this version of Python and of Mac OS X.\ \b \ul \ +Certificate verification and OpenSSL\ + +\b0 \ulnone \ +Python 3.5 includes a number of network security enhancements that were released in Python 3.4.3 and Python 2.7.10. {\field{\*\fldinst{HYPERLINK "https://www.python.org/dev/peps/pep-0476/"}}{\fldrslt PEP 476}} changes several standard library modules, like +\i httplib +\i0 , +\i urllib +\i0 , and +\i xmlrpclib +\i0 , to by default verify certificates presented by servers over secure (TLS) connections. The verification is performed by the OpenSSL libraries that Python is linked to. Prior to 3.4.3, both python.org installers dynamically linked with Apple-supplied OpenSSL libraries shipped with OS X. OS X provides a multiple level security framework that stores trust certificates in system and user keychains managed by the +\i Keychain Access +\i0 application and the +\i security +\i0 command line utility.\ +\ +For OS X 10.5, Apple provides +\i OpenSSL 0.9.7 +\i0 libraries. This version of Apple's OpenSSL +\b does not +\b0 use the certificates from the system security framework, even when used on newer versions of OS X. Instead it consults a traditional OpenSSL concatenated certificate file ( +\i cafile +\i0 ) or certificate directory ( +\i capath +\i0 ), located in +\f1 /System/Library/OpenSSL +\f0 . These directories are typically empty and not managed by OS X; you must manage them yourself or supply your own SSL contexts. OpenSSL 0.9.7 is obsolete by current security standards, lacking a number of important features found in later versions. Among the problems this causes is the inability to verify higher-security certificates now used by python.org services, including +\i t{\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi"}}{\fldrslt he Python Package Index, PyPI}} +\i0 . To solve this problem, the +\i 10.5+ 32-bit-only python.org variant +\i0 is linked with a private copy of +\i OpenSSL 1.0.2 +\i0 ; it consults the same default certificate directory, +\f1 /System/Library/OpenSSL +\f0 . As before, it is still necessary to manage certificates yourself when you use this Python variant and, with certificate verification now enabled by default, you may now need to take additional steps to ensure your Python programs have access to CA certificates you trust. If you use this Python variant to build standalone applications with third-party tools like {\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi/py2app/"}}{\fldrslt +\f1 py2app}}, you may now need to bundle CA certificates in them or otherwise supply non-default SSL contexts.\ +\ +For OS X 10.6+, Apple also provides +\i OpenSSL +\i0 +\i 0.9.8 libraries +\i0 . Apple's 0.9.8 version includes an important additional feature: if a certificate cannot be verified using the manually administered certificates in +\f1 /System/Library/OpenSSL +\f0 , the certificates managed by the system security framework In the user and system keychains are also consulted (using Apple private APIs). For this reason, the +\i 64-bit/32-bit 10.6+ python.org variant +\i0 continues to be dynamically linked with Apple's OpenSSL 0.9.8 since it was felt that the loss of the system-provided certificates and management tools outweighs the additional security features provided by newer versions of OpenSSL. This will likely change in future releases of the python.org installers as Apple has deprecated use of the system-supplied OpenSSL libraries. If you do need features from newer versions of OpenSSL, there are third-party OpenSSL wrapper packages available through +\i PyPI +\i0 .\ +\ +The bundled +\f1 pip +\f0 included with the Python 3.5 installers has its own default certificate store for verifying download connections.\ +\ + +\b \ul Other changes\ + +\b0 \ulnone \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural +\cf0 For other changes in this release, see the +\i What's new +\i0 section in the {\field{\*\fldinst{HYPERLINK "https://www.python.org/doc/"}}{\fldrslt Documentation Set}} for this release and its +\i Release Notes +\i0 link at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural + +\b \cf0 \ul \ Python 3 and Python 2 Co-existence\ \b0 \ulnone \ diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip --- a/Mac/BuildScript/scripts/postflight.ensurepip +++ b/Mac/BuildScript/scripts/postflight.ensurepip @@ -10,15 +10,15 @@ umask 022 -"${FWK}/bin/python${PYVER}" -m ensurepip --upgrade +"${FWK}/bin/python${PYVER}" -E -s -m ensurepip --upgrade -"${FWK}/bin/python${PYVER}" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python${PYVER}" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -"${FWK}/bin/python${PYVER}" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python${PYVER}" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" diff --git a/Mac/BuildScript/scripts/postflight.framework b/Mac/BuildScript/scripts/postflight.framework --- a/Mac/BuildScript/scripts/postflight.framework +++ b/Mac/BuildScript/scripts/postflight.framework @@ -6,23 +6,23 @@ PYVER="@PYVER@" FWK="/Library/Frameworks/Python.framework/Versions/@PYVER@" -"${FWK}/bin/python at PYVER@" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ "${FWK}/lib/python${PYVER}" -"${FWK}/bin/python at PYVER@" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ "${FWK}/lib/python${PYVER}" -"${FWK}/bin/python at PYVER@" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -"${FWK}/bin/python at PYVER@" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 08:55:59 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 06:55:59 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Updates_to_the?= =?utf-8?q?_OS_X_installer_for_3=2E5=2E0b3=3A?= Message-ID: <20150704065559.14764.71239@psf.io> https://hg.python.org/cpython/rev/212a436483d6 changeset: 96796:212a436483d6 branch: 3.5 parent: 96794:bbf4e35ed69e user: Ned Deily date: Fri Jul 03 23:53:51 2015 -0700 summary: Updates to the OS X installer for 3.5.0b3: - update installer ReadMe file - suppress installer per-file byte-compilation messages to system log - speed up installer byte-compilation - isolate ensurepip install from user site-packages files: Mac/BuildScript/resources/ReadMe.rtf | 69 +++++++++- Mac/BuildScript/scripts/postflight.ensurepip | 10 +- Mac/BuildScript/scripts/postflight.framework | 16 +- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1347\cocoasubrtf570 +{\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} \margl1440\margr1440\vieww13380\viewh14600\viewkind0 @@ -24,7 +24,7 @@ \i0 variant. Unless you are installing to an 10.5 system or you need to build applications that can run on 10.5 systems, use the 10.6 variant if possible. There are some additional operating system functions that are supported starting with 10.6 and you may see better performance using 64-bit mode. By default, Python will automatically run in 64-bit mode if your system supports it. Also see \i Certificate verification and OpenSSL \i0 below. The Pythons installed by these installers are built with private copies of some third-party libraries not included with or newer than those in OS X itself. The list of these libraries varies by installer variant and is included at the end of the License.rtf file. -\b \ul \ulc0 \ +\b \ul \ \ Update your version of Tcl/Tk to use IDLE or other Tk applications \b0 \ulnone \ @@ -36,6 +36,71 @@ \i0 for this version of Python and of Mac OS X.\ \b \ul \ +Certificate verification and OpenSSL\ + +\b0 \ulnone \ +Python 3.5 includes a number of network security enhancements that were released in Python 3.4.3 and Python 2.7.10. {\field{\*\fldinst{HYPERLINK "https://www.python.org/dev/peps/pep-0476/"}}{\fldrslt PEP 476}} changes several standard library modules, like +\i httplib +\i0 , +\i urllib +\i0 , and +\i xmlrpclib +\i0 , to by default verify certificates presented by servers over secure (TLS) connections. The verification is performed by the OpenSSL libraries that Python is linked to. Prior to 3.4.3, both python.org installers dynamically linked with Apple-supplied OpenSSL libraries shipped with OS X. OS X provides a multiple level security framework that stores trust certificates in system and user keychains managed by the +\i Keychain Access +\i0 application and the +\i security +\i0 command line utility.\ +\ +For OS X 10.5, Apple provides +\i OpenSSL 0.9.7 +\i0 libraries. This version of Apple's OpenSSL +\b does not +\b0 use the certificates from the system security framework, even when used on newer versions of OS X. Instead it consults a traditional OpenSSL concatenated certificate file ( +\i cafile +\i0 ) or certificate directory ( +\i capath +\i0 ), located in +\f1 /System/Library/OpenSSL +\f0 . These directories are typically empty and not managed by OS X; you must manage them yourself or supply your own SSL contexts. OpenSSL 0.9.7 is obsolete by current security standards, lacking a number of important features found in later versions. Among the problems this causes is the inability to verify higher-security certificates now used by python.org services, including +\i t{\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi"}}{\fldrslt he Python Package Index, PyPI}} +\i0 . To solve this problem, the +\i 10.5+ 32-bit-only python.org variant +\i0 is linked with a private copy of +\i OpenSSL 1.0.2 +\i0 ; it consults the same default certificate directory, +\f1 /System/Library/OpenSSL +\f0 . As before, it is still necessary to manage certificates yourself when you use this Python variant and, with certificate verification now enabled by default, you may now need to take additional steps to ensure your Python programs have access to CA certificates you trust. If you use this Python variant to build standalone applications with third-party tools like {\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi/py2app/"}}{\fldrslt +\f1 py2app}}, you may now need to bundle CA certificates in them or otherwise supply non-default SSL contexts.\ +\ +For OS X 10.6+, Apple also provides +\i OpenSSL +\i0 +\i 0.9.8 libraries +\i0 . Apple's 0.9.8 version includes an important additional feature: if a certificate cannot be verified using the manually administered certificates in +\f1 /System/Library/OpenSSL +\f0 , the certificates managed by the system security framework In the user and system keychains are also consulted (using Apple private APIs). For this reason, the +\i 64-bit/32-bit 10.6+ python.org variant +\i0 continues to be dynamically linked with Apple's OpenSSL 0.9.8 since it was felt that the loss of the system-provided certificates and management tools outweighs the additional security features provided by newer versions of OpenSSL. This will likely change in future releases of the python.org installers as Apple has deprecated use of the system-supplied OpenSSL libraries. If you do need features from newer versions of OpenSSL, there are third-party OpenSSL wrapper packages available through +\i PyPI +\i0 .\ +\ +The bundled +\f1 pip +\f0 included with the Python 3.5 installers has its own default certificate store for verifying download connections.\ +\ + +\b \ul Other changes\ + +\b0 \ulnone \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural +\cf0 For other changes in this release, see the +\i What's new +\i0 section in the {\field{\*\fldinst{HYPERLINK "https://www.python.org/doc/"}}{\fldrslt Documentation Set}} for this release and its +\i Release Notes +\i0 link at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural + +\b \cf0 \ul \ Python 3 and Python 2 Co-existence\ \b0 \ulnone \ diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip --- a/Mac/BuildScript/scripts/postflight.ensurepip +++ b/Mac/BuildScript/scripts/postflight.ensurepip @@ -10,15 +10,15 @@ umask 022 -"${FWK}/bin/python${PYVER}" -m ensurepip --upgrade +"${FWK}/bin/python${PYVER}" -E -s -m ensurepip --upgrade -"${FWK}/bin/python${PYVER}" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python${PYVER}" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -"${FWK}/bin/python${PYVER}" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python${PYVER}" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" diff --git a/Mac/BuildScript/scripts/postflight.framework b/Mac/BuildScript/scripts/postflight.framework --- a/Mac/BuildScript/scripts/postflight.framework +++ b/Mac/BuildScript/scripts/postflight.framework @@ -6,23 +6,23 @@ PYVER="@PYVER@" FWK="/Library/Frameworks/Python.framework/Versions/@PYVER@" -"${FWK}/bin/python at PYVER@" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ "${FWK}/lib/python${PYVER}" -"${FWK}/bin/python at PYVER@" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ "${FWK}/lib/python${PYVER}" -"${FWK}/bin/python at PYVER@" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -"${FWK}/bin/python at PYVER@" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sat Jul 4 10:45:31 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 04 Jul 2015 08:45:31 +0000 Subject: [Python-checkins] Daily reference leaks (596ca185e3dc): sum=4 Message-ID: <20150704084531.23363.11129@psf.io> results for 596ca185e3dc on branch "default" -------------------------------------------- test_functools leaked [0, 2, 2] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogjZemfX', '--timeout', '7200'] From python-checkins at python.org Sat Jul 4 17:46:36 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 04 Jul 2015 15:46:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_cleanup=2E?= Message-ID: <20150704154636.113878.27734@psf.io> https://hg.python.org/cpython/rev/7ed4503b73a7 changeset: 96798:7ed4503b73a7 user: Raymond Hettinger date: Sat Jul 04 08:46:31 2015 -0700 summary: Minor cleanup. files: Objects/setobject.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -963,7 +963,7 @@ * incrementally resizing as we insert new keys. Expect * that there will be no (or few) overlapping keys. */ - if (dictsize == -1) + if (dictsize < 0) return -1; if ((so->fill + dictsize)*3 >= so->mask*2) { if (set_table_resize(so, so->used + dictsize) != 0) @@ -1457,7 +1457,7 @@ entry.key = key; rv = set_contains_entry(so, &entry); Py_DECREF(key); - if (rv == -1) { + if (rv < 0) { Py_DECREF(it); return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 20:28:39 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 04 Jul 2015 18:28:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Make_sure_the_dummy_percen?= =?utf-8?q?tage_calculation_won=27t_overflow=2E?= Message-ID: <20150704182839.15859.17933@psf.io> https://hg.python.org/cpython/rev/9ac2169463b7 changeset: 96799:9ac2169463b7 user: Raymond Hettinger date: Sat Jul 04 11:28:35 2015 -0700 summary: Make sure the dummy percentage calculation won't overflow. files: Objects/setobject.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1506,8 +1506,8 @@ if (PyErr_Occurred()) return -1; } - /* If more than 1/5 are dummies, then resize them away. */ - if ((so->fill - so->used) * 5 < so->mask) + /* If more than 1/4th are dummies, then resize them away. */ + if ((size_t)(so->fill - so->used) <= (size_t)so->mask / 4) return 0; return set_table_resize(so, so->used); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 20:49:35 2015 From: python-checkins at python.org (steve.dower) Date: Sat, 04 Jul 2015 18:49:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Ignore_user_en?= =?utf-8?q?vironment/site-packages_for_ensurepip_and_compile=5Fall?= Message-ID: <20150704184935.64447.3731@psf.io> https://hg.python.org/cpython/rev/ff1b9f0cf9ee changeset: 96800:ff1b9f0cf9ee branch: 3.5 parent: 96796:212a436483d6 user: Steve Dower date: Sat Jul 04 11:48:37 2015 -0700 summary: Ignore user environment/site-packages for ensurepip and compile_all Remove build condition to prevent old strings hanging around Add -h option to build.bat files: Tools/msi/build.bat | 16 ++++++++- Tools/msi/bundle/packagegroups/postinstall.wxs | 2 +- Tools/msi/msi.targets | 2 +- Tools/msi/pip/pip.wxs | 4 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Tools/msi/build.bat b/Tools/msi/build.bat --- a/Tools/msi/build.bat +++ b/Tools/msi/build.bat @@ -8,9 +8,10 @@ set BUILDDOC= :CheckOpts -if '%1'=='-x86' (set BUILDX86=1) && shift && goto CheckOpts -if '%1'=='-x64' (set BUILDX64=1) && shift && goto CheckOpts -if '%1'=='--doc' (set BUILDDOC=1) && shift && goto CheckOpts +if "%1" EQU "-h" goto Help +if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts +if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts +if "%1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) @@ -44,3 +45,12 @@ msbuild "%D%bundle\snapshot.wixproj" /p:Platform=x64 if errorlevel 1 goto :eof ) + +exit /B 0 + +:Help +echo build.bat [-x86] [-x64] [--doc] [-h] +echo. +echo -x86 Build x86 installers +echo -x64 Build x64 installers +echo --doc Build CHM documentation diff --git a/Tools/msi/bundle/packagegroups/postinstall.wxs b/Tools/msi/bundle/packagegroups/postinstall.wxs --- a/Tools/msi/bundle/packagegroups/postinstall.wxs +++ b/Tools/msi/bundle/packagegroups/postinstall.wxs @@ -36,7 +36,7 @@ - + - + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) diff --git a/Tools/msi/pip/pip.wxs b/Tools/msi/pip/pip.wxs --- a/Tools/msi/pip/pip.wxs +++ b/Tools/msi/pip/pip.wxs @@ -27,8 +27,8 @@ - - + + (&DefaultFeature=3) AND NOT (!DefaultFeature=3) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 20:49:35 2015 From: python-checkins at python.org (steve.dower) Date: Sat, 04 Jul 2015 18:49:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Ignore_user_environment/site-packages_for_ensurepip_and_?= =?utf-8?q?compile=5Fall?= Message-ID: <20150704184935.4356.54504@psf.io> https://hg.python.org/cpython/rev/aadf3f60a9ef changeset: 96801:aadf3f60a9ef parent: 96799:9ac2169463b7 parent: 96800:ff1b9f0cf9ee user: Steve Dower date: Sat Jul 04 11:48:59 2015 -0700 summary: Ignore user environment/site-packages for ensurepip and compile_all Remove build condition to prevent old strings hanging around Add -h option to build.bat files: Tools/msi/build.bat | 16 ++++++++- Tools/msi/bundle/packagegroups/postinstall.wxs | 2 +- Tools/msi/msi.targets | 2 +- Tools/msi/pip/pip.wxs | 4 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Tools/msi/build.bat b/Tools/msi/build.bat --- a/Tools/msi/build.bat +++ b/Tools/msi/build.bat @@ -8,9 +8,10 @@ set BUILDDOC= :CheckOpts -if '%1'=='-x86' (set BUILDX86=1) && shift && goto CheckOpts -if '%1'=='-x64' (set BUILDX64=1) && shift && goto CheckOpts -if '%1'=='--doc' (set BUILDDOC=1) && shift && goto CheckOpts +if "%1" EQU "-h" goto Help +if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts +if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts +if "%1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) @@ -44,3 +45,12 @@ msbuild "%D%bundle\snapshot.wixproj" /p:Platform=x64 if errorlevel 1 goto :eof ) + +exit /B 0 + +:Help +echo build.bat [-x86] [-x64] [--doc] [-h] +echo. +echo -x86 Build x86 installers +echo -x64 Build x64 installers +echo --doc Build CHM documentation diff --git a/Tools/msi/bundle/packagegroups/postinstall.wxs b/Tools/msi/bundle/packagegroups/postinstall.wxs --- a/Tools/msi/bundle/packagegroups/postinstall.wxs +++ b/Tools/msi/bundle/packagegroups/postinstall.wxs @@ -36,7 +36,7 @@ - + - + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) diff --git a/Tools/msi/pip/pip.wxs b/Tools/msi/pip/pip.wxs --- a/Tools/msi/pip/pip.wxs +++ b/Tools/msi/pip/pip.wxs @@ -27,8 +27,8 @@ - - + + (&DefaultFeature=3) AND NOT (!DefaultFeature=3) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 21:46:29 2015 From: python-checkins at python.org (r.david.murray) Date: Sat, 04 Jul 2015 19:46:29 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Merge=3A_=2324584=3A_replace_dead_link_with_pointer_to_archive?= =?utf-8?b?Lm9yZy4=?= Message-ID: <20150704194629.107534.24084@psf.io> https://hg.python.org/cpython/rev/51e05ee9848a changeset: 96803:51e05ee9848a branch: 3.5 parent: 96800:ff1b9f0cf9ee parent: 96802:050a941f69fb user: R David Murray date: Sat Jul 04 15:45:41 2015 -0400 summary: Merge: #24584: replace dead link with pointer to archive.org. 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 @@ -47,7 +47,7 @@ Module :mod:`doctest` Another test-support module with a very different flavor. - `Simple Smalltalk Testing: With Patterns `_ + `Simple Smalltalk Testing: With Patterns `_ Kent Beck's original paper on testing frameworks using the pattern shared by :mod:`unittest`. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 21:46:29 2015 From: python-checkins at python.org (r.david.murray) Date: Sat, 04 Jul 2015 19:46:29 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogIzI0NTg0OiByZXBs?= =?utf-8?q?ace_dead_link_with_pointer_to_archive=2Eorg=2E?= Message-ID: <20150704194629.68844.96938@psf.io> https://hg.python.org/cpython/rev/050a941f69fb changeset: 96802:050a941f69fb branch: 3.4 parent: 96793:4b52fce3753d user: R David Murray date: Sat Jul 04 15:44:14 2015 -0400 summary: #24584: replace dead link with pointer to archive.org. 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 @@ -47,7 +47,7 @@ Module :mod:`doctest` Another test-support module with a very different flavor. - `Simple Smalltalk Testing: With Patterns `_ + `Simple Smalltalk Testing: With Patterns `_ Kent Beck's original paper on testing frameworks using the pattern shared by :mod:`unittest`. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 21:46:29 2015 From: python-checkins at python.org (r.david.murray) Date: Sat, 04 Jul 2015 19:46:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_=2324584=3A_replace_dead_link_with_pointer_to_a?= =?utf-8?q?rchive=2Eorg=2E?= Message-ID: <20150704194629.130183.14298@psf.io> https://hg.python.org/cpython/rev/631ef17fc772 changeset: 96804:631ef17fc772 parent: 96801:aadf3f60a9ef parent: 96803:51e05ee9848a user: R David Murray date: Sat Jul 04 15:46:14 2015 -0400 summary: Merge: #24584: replace dead link with pointer to archive.org. 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 @@ -47,7 +47,7 @@ Module :mod:`doctest` Another test-support module with a very different flavor. - `Simple Smalltalk Testing: With Patterns `_ + `Simple Smalltalk Testing: With Patterns `_ Kent Beck's original paper on testing frameworks using the pattern shared by :mod:`unittest`. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Jul 4 21:50:38 2015 From: python-checkins at python.org (r.david.murray) Date: Sat, 04 Jul 2015 19:50:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzI0NTQ4OiByZXBs?= =?utf-8?q?ace_dead_link_with_pointer_to_archive=2Eorg=2E?= Message-ID: <20150704195038.102267.6742@psf.io> https://hg.python.org/cpython/rev/5f279db087e7 changeset: 96805:5f279db087e7 branch: 2.7 parent: 96792:695bbbaf2478 user: R David Murray date: Sat Jul 04 15:50:30 2015 -0400 summary: #24548: replace dead link with pointer to archive.org. 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 @@ -83,7 +83,7 @@ discovery. unittest2 allows you to use these features with earlier versions of Python. - `Simple Smalltalk Testing: With Patterns `_ + `Simple Smalltalk Testing: With Patterns `_ Kent Beck's original paper on testing frameworks using the pattern shared by :mod:`unittest`. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 00:07:05 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 22:07:05 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2324330=3A_merge_from_3=2E5?= Message-ID: <20150704220704.19983.95993@psf.io> https://hg.python.org/cpython/rev/055ddc0e713b changeset: 96809:055ddc0e713b parent: 96804:631ef17fc772 parent: 96808:2dfdbbe0701b user: Ned Deily date: Sat Jul 04 15:06:43 2015 -0700 summary: Issue #24330: merge from 3.5 files: Doc/library/idle.rst | 3 ++- Lib/idlelib/help.txt | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -248,7 +248,8 @@ help sources can be specified. Non-default user setting are saved in a .idlerc directory in the user's home directory. Problems caused by bad user configuration files are solved by editing or deleting one or more of the - files in .idlerc. + files in .idlerc. On OS X, open the configuration dialog by selecting + Preferences in the application menu. Configure Extensions Open a configuration dialog for setting preferences for extensions diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -129,7 +129,9 @@ Configure IDLE -- Open a configuration dialog. Fonts, indentation, keybindings, and color themes may be altered. Startup Preferences may be set, and additional Help - sources can be specified. + sources can be specified. On OS X, open the + configuration dialog by selecting Preferences + in the application menu. --- Code Context (toggle) -- Open a pane at the top of the edit window -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 00:07:04 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 22:07:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0MzMw?= =?utf-8?q?=3A_Update_IDLE_doc_and_help_to_note_=22Configure_IDLE=22_diffe?= =?utf-8?q?rence?= Message-ID: <20150704220704.8473.28121@psf.io> https://hg.python.org/cpython/rev/64b42ec6ef42 changeset: 96806:64b42ec6ef42 branch: 2.7 user: Ned Deily date: Sat Jul 04 15:04:42 2015 -0700 summary: Issue #24330: Update IDLE doc and help to note "Configure IDLE" difference on OS X. Original patch by Andr? Freitas. files: Doc/library/idle.rst | 3 ++- Lib/idlelib/help.txt | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -248,7 +248,8 @@ help sources can be specified. Non-default user setting are saved in a .idlerc directory in the user's home directory. Problems caused by bad user configuration files are solved by editing or deleting one or more of the - files in .idlerc. + files in .idlerc. On OS X, open the configuration dialog by selecting + Preferences in the application menu. Configure Extensions Open a configuration dialog for setting preferences for extensions diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -90,10 +90,9 @@ Configure IDLE -- Open a configuration dialog. Fonts, indentation, keybindings, and color themes may be altered. Startup Preferences may be set, and Additional Help - Sources can be specified. - - On OS X this menu is not present, use - menu 'IDLE -> Preferences...' instead. + Sources can be specified. On OS X, open the + configuration dialog by selecting Preferences + in the application menu. --- Code Context -- Open a pane at the top of the edit window which shows the block context of the section of code -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 00:07:04 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 22:07:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Issue_=2324330=3A_merge_from_3=2E4?= Message-ID: <20150704220704.1848.51980@psf.io> https://hg.python.org/cpython/rev/2dfdbbe0701b changeset: 96808:2dfdbbe0701b branch: 3.5 parent: 96803:51e05ee9848a parent: 96807:b9460ee09228 user: Ned Deily date: Sat Jul 04 15:06:21 2015 -0700 summary: Issue #24330: merge from 3.4 files: Doc/library/idle.rst | 3 ++- Lib/idlelib/help.txt | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -248,7 +248,8 @@ help sources can be specified. Non-default user setting are saved in a .idlerc directory in the user's home directory. Problems caused by bad user configuration files are solved by editing or deleting one or more of the - files in .idlerc. + files in .idlerc. On OS X, open the configuration dialog by selecting + Preferences in the application menu. Configure Extensions Open a configuration dialog for setting preferences for extensions diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -129,7 +129,9 @@ Configure IDLE -- Open a configuration dialog. Fonts, indentation, keybindings, and color themes may be altered. Startup Preferences may be set, and additional Help - sources can be specified. + sources can be specified. On OS X, open the + configuration dialog by selecting Preferences + in the application menu. --- Code Context (toggle) -- Open a pane at the top of the edit window -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 00:07:04 2015 From: python-checkins at python.org (ned.deily) Date: Sat, 04 Jul 2015 22:07:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI0MzMw?= =?utf-8?q?=3A_Update_IDLE_doc_and_help_to_note_=22Configure_IDLE=22_diffe?= =?utf-8?q?rence?= Message-ID: <20150704220704.113878.76254@psf.io> https://hg.python.org/cpython/rev/b9460ee09228 changeset: 96807:b9460ee09228 branch: 3.4 parent: 96802:050a941f69fb user: Ned Deily date: Sat Jul 04 15:05:07 2015 -0700 summary: Issue #24330: Update IDLE doc and help to note "Configure IDLE" difference on OS X. Original patch by Andr? Freitas. files: Doc/library/idle.rst | 3 ++- Lib/idlelib/help.txt | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -248,7 +248,8 @@ help sources can be specified. Non-default user setting are saved in a .idlerc directory in the user's home directory. Problems caused by bad user configuration files are solved by editing or deleting one or more of the - files in .idlerc. + files in .idlerc. On OS X, open the configuration dialog by selecting + Preferences in the application menu. Configure Extensions Open a configuration dialog for setting preferences for extensions diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -129,7 +129,9 @@ Configure IDLE -- Open a configuration dialog. Fonts, indentation, keybindings, and color themes may be altered. Startup Preferences may be set, and additional Help - sources can be specified. + sources can be specified. On OS X, open the + configuration dialog by selecting Preferences + in the application menu. --- Code Context (toggle) -- Open a pane at the top of the edit window -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 01:04:50 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 04 Jul 2015 23:04:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Make_the_unicode_equality_?= =?utf-8?q?test_an_external_function_rather_than_in-lining_it=2E?= Message-ID: <20150704230449.9573.83416@psf.io> https://hg.python.org/cpython/rev/7900983373f0 changeset: 96810:7900983373f0 user: Raymond Hettinger date: Sat Jul 04 16:04:44 2015 -0700 summary: Make the unicode equality test an external function rather than in-lining it. The real benefit of the unicode specialized function comes from bypassing the overhead of PyObject_RichCompareBool() and not from being in-lined (especially since there was almost no shared data between the caller and callee). Also, the in-lining was having a negative effect on code generation for the callee. files: Include/unicodeobject.h | 4 ++++ Objects/setobject.c | 9 ++++----- Objects/unicodeobject.c | 7 +++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -2261,6 +2261,10 @@ /* Clear all static strings. */ PyAPI_FUNC(void) _PyUnicode_ClearStaticStrings(void); +/* Fast equality check when the inputs are known to be exact unicode types + and where the hash values are equal (i.e. a very probable match) */ +PyAPI_FUNC(int) _PyUnicode_EQ(PyObject *, PyObject *); + #ifdef __cplusplus } #endif diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -29,7 +29,6 @@ #include "Python.h" #include "structmember.h" -#include "stringlib/eq.h" /* Object used as dummy key to fill deleted entries */ static PyObject _dummy_struct; @@ -74,7 +73,7 @@ return entry; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) + && _PyUnicode_EQ(startkey, key)) return entry; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -100,7 +99,7 @@ return entry; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) + && _PyUnicode_EQ(startkey, key)) return entry; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -155,7 +154,7 @@ goto found_active; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) + && _PyUnicode_EQ(startkey, key)) goto found_active; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -183,7 +182,7 @@ goto found_active; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) + && _PyUnicode_EQ(startkey, key)) goto found_active; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -42,6 +42,7 @@ #include "Python.h" #include "ucnhash.h" #include "bytes_methods.h" +#include "stringlib/eq.h" #ifdef MS_WINDOWS #include @@ -10887,6 +10888,12 @@ } int +_PyUnicode_EQ(PyObject *aa, PyObject *bb) +{ + return unicode_eq(aa, bb); +} + +int PyUnicode_Contains(PyObject *container, PyObject *element) { PyObject *str, *sub; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 05:54:13 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 03:54:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy41ICgjMjQ0MDcp?= Message-ID: <20150705035413.19423.16654@psf.io> https://hg.python.org/cpython/rev/88814ddd5e9e changeset: 96814:88814ddd5e9e parent: 96780:a14f6a70d013 parent: 96813:6a7ee97cb0b1 user: Benjamin Peterson date: Sat Jul 04 19:59:50 2015 -0500 summary: merge 3.5 (#24407) files: Lib/test/test_dict.py | 14 ++++++++++++++ Misc/NEWS | 2 ++ Objects/dictobject.c | 26 +++++++++++++++++++------- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -937,6 +937,20 @@ d.popitem() self.check_reentrant_insertion(mutate) + def test_merge_and_mutate(self): + class X: + def __hash__(self): + return 0 + + def __eq__(self, o): + other.clear() + return False + + l = [(i,0) for i in range(1, 1337)] + other = dict(l) + other[X()] = 0 + d = {X(): 0, 1: 1} + self.assertRaises(RuntimeError, d.update, other) from test import mapping_tests diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,8 @@ - Issue #19235: Add new RecursionError exception. Patch by Georg Brandl. +- Issue #24407: Fix crash when dict is mutated while being updated. + Library ------- diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2039,20 +2039,32 @@ if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) return -1; for (i = 0, n = DK_SIZE(other->ma_keys); i < n; i++) { - PyObject *value; + PyObject *key, *value; + Py_hash_t hash; entry = &other->ma_keys->dk_entries[i]; + key = entry->me_key; + hash = entry->me_hash; if (other->ma_values) value = other->ma_values[i]; else value = entry->me_value; - if (value != NULL && - (override || - PyDict_GetItem(a, entry->me_key) == NULL)) { - if (insertdict(mp, entry->me_key, - entry->me_hash, - value) != 0) + if (value != NULL) { + int err = 0; + Py_INCREF(key); + Py_INCREF(value); + if (override || PyDict_GetItem(a, key) == NULL) + err = insertdict(mp, key, hash, value); + Py_DECREF(value); + Py_DECREF(key); + if (err != 0) return -1; + + if (n != DK_SIZE(other->ma_keys)) { + PyErr_SetString(PyExc_RuntimeError, + "dict mutated during update"); + return -1; + } } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 05:54:13 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 03:54:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3_=28=2324407=29?= Message-ID: <20150705035413.105249.58401@psf.io> https://hg.python.org/cpython/rev/75da5acbfbe4 changeset: 96812:75da5acbfbe4 branch: 3.4 parent: 96769:34460219c0e0 parent: 96811:37fed8b02f00 user: Benjamin Peterson date: Sat Jul 04 19:58:11 2015 -0500 summary: merge 3.3 (#24407) files: Lib/test/test_dict.py | 14 ++++++++++++++ Misc/NEWS | 2 ++ Objects/dictobject.c | 26 +++++++++++++++++++------- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -937,6 +937,20 @@ d.popitem() self.check_reentrant_insertion(mutate) + def test_merge_and_mutate(self): + class X: + def __hash__(self): + return 0 + + def __eq__(self, o): + other.clear() + return False + + l = [(i,0) for i in range(1, 1337)] + other = dict(l) + other[X()] = 0 + d = {X(): 0, 1: 1} + self.assertRaises(RuntimeError, d.update, other) from test import mapping_tests diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -32,6 +32,8 @@ - Issue #23757: PySequence_Tuple() incorrectly called the concrete list API when the data was a list subclass. +- Issue #24407: Fix crash when dict is mutated while being updated. + - Issue #24096: Make warnings.warn_explicit more robust against mutation of the warnings.filters list. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1973,20 +1973,32 @@ if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) return -1; for (i = 0, n = DK_SIZE(other->ma_keys); i < n; i++) { - PyObject *value; + PyObject *key, *value; + Py_hash_t hash; entry = &other->ma_keys->dk_entries[i]; + key = entry->me_key; + hash = entry->me_hash; if (other->ma_values) value = other->ma_values[i]; else value = entry->me_value; - if (value != NULL && - (override || - PyDict_GetItem(a, entry->me_key) == NULL)) { - if (insertdict(mp, entry->me_key, - entry->me_hash, - value) != 0) + if (value != NULL) { + int err = 0; + Py_INCREF(key); + Py_INCREF(value); + if (override || PyDict_GetItem(a, key) == NULL) + err = insertdict(mp, key, hash, value); + Py_DECREF(value); + Py_DECREF(key); + if (err != 0) return -1; + + if (n != DK_SIZE(other->ma_keys)) { + PyErr_SetString(PyExc_RuntimeError, + "dict mutated during update"); + return -1; + } } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 05:54:13 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 03:54:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_merge_3=2E4_=28=2324407=29?= Message-ID: <20150705035413.27420.84815@psf.io> https://hg.python.org/cpython/rev/6a7ee97cb0b1 changeset: 96813:6a7ee97cb0b1 branch: 3.5 parent: 96779:cb1aafc9ad7e parent: 96812:75da5acbfbe4 user: Benjamin Peterson date: Sat Jul 04 19:59:24 2015 -0500 summary: merge 3.4 (#24407) files: Lib/test/test_dict.py | 14 ++++++++++++++ Misc/NEWS | 2 ++ Objects/dictobject.c | 26 +++++++++++++++++++------- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -937,6 +937,20 @@ d.popitem() self.check_reentrant_insertion(mutate) + def test_merge_and_mutate(self): + class X: + def __hash__(self): + return 0 + + def __eq__(self, o): + other.clear() + return False + + l = [(i,0) for i in range(1, 1337)] + other = dict(l) + other[X()] = 0 + d = {X(): 0, 1: 1} + self.assertRaises(RuntimeError, d.update, other) from test import mapping_tests diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,8 @@ - Issue #19235: Add new RecursionError exception. Patch by Georg Brandl. +- Issue #24407: Fix crash when dict is mutated while being updated. + Library ------- diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2039,20 +2039,32 @@ if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) return -1; for (i = 0, n = DK_SIZE(other->ma_keys); i < n; i++) { - PyObject *value; + PyObject *key, *value; + Py_hash_t hash; entry = &other->ma_keys->dk_entries[i]; + key = entry->me_key; + hash = entry->me_hash; if (other->ma_values) value = other->ma_values[i]; else value = entry->me_value; - if (value != NULL && - (override || - PyDict_GetItem(a, entry->me_key) == NULL)) { - if (insertdict(mp, entry->me_key, - entry->me_hash, - value) != 0) + if (value != NULL) { + int err = 0; + Py_INCREF(key); + Py_INCREF(value); + if (override || PyDict_GetItem(a, key) == NULL) + err = insertdict(mp, key, hash, value); + Py_DECREF(value); + Py_DECREF(key); + if (err != 0) return -1; + + if (n != DK_SIZE(other->ma_keys)) { + PyErr_SetString(PyExc_RuntimeError, + "dict mutated during update"); + return -1; + } } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 05:54:13 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 03:54:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_protect_agains?= =?utf-8?q?t_mutation_of_the_dict_during_insertion_=28closes_=2324407=29?= Message-ID: <20150705035413.22962.35239@psf.io> https://hg.python.org/cpython/rev/37fed8b02f00 changeset: 96811:37fed8b02f00 branch: 3.3 parent: 96688:8daf7b74462a user: Benjamin Peterson date: Sat Jul 04 19:55:16 2015 -0500 summary: protect against mutation of the dict during insertion (closes #24407) files: Lib/test/test_dict.py | 15 +++++++++++++++ Misc/NEWS | 2 ++ Objects/dictobject.c | 26 +++++++++++++++++++------- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -906,6 +906,21 @@ f.a = 'a' self.assertEqual(f.__dict__, {1:1, 'a':'a'}) + def test_merge_and_mutate(self): + class X: + def __hash__(self): + return 0 + + def __eq__(self, o): + other.clear() + return False + + l = [(i,0) for i in range(1, 1337)] + other = dict(l) + other[X()] = 0 + d = {X(): 0, 1: 1} + self.assertRaises(RuntimeError, d.update, other) + from test import mapping_tests class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #24407: Fix crash when dict is mutated while being updated. + - Issue #24096: Make warnings.warn_explicit more robust against mutation of the warnings.filters list. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1941,20 +1941,32 @@ if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) return -1; for (i = 0, n = DK_SIZE(other->ma_keys); i < n; i++) { - PyObject *value; + PyObject *key, *value; + Py_hash_t hash; entry = &other->ma_keys->dk_entries[i]; + key = entry->me_key; + hash = entry->me_hash; if (other->ma_values) value = other->ma_values[i]; else value = entry->me_value; - if (value != NULL && - (override || - PyDict_GetItem(a, entry->me_key) == NULL)) { - if (insertdict(mp, entry->me_key, - entry->me_hash, - value) != 0) + if (value != NULL) { + int err = 0; + Py_INCREF(key); + Py_INCREF(value); + if (override || PyDict_GetItem(a, key) == NULL) + err = insertdict(mp, key, hash, value); + Py_DECREF(value); + Py_DECREF(key); + if (err != 0) return -1; + + if (n != DK_SIZE(other->ma_keys)) { + PyErr_SetString(PyExc_RuntimeError, + "dict mutated during update"); + return -1; + } } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 05:54:14 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 03:54:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNCk6?= =?utf-8?q?_merge_heads?= Message-ID: <20150705035414.15972.24288@psf.io> https://hg.python.org/cpython/rev/725131a5f6cf changeset: 96815:725131a5f6cf branch: 3.4 parent: 96812:75da5acbfbe4 parent: 96807:b9460ee09228 user: Benjamin Peterson date: Sat Jul 04 22:52:33 2015 -0500 summary: merge heads files: Doc/library/idle.rst | 3 ++- Doc/library/unittest.rst | 2 +- Lib/idlelib/help.txt | 4 +++- Mac/BuildScript/build-installer.py | 6 +++--- Mac/BuildScript/openssl_sdk_makedepend.patch | 2 +- Misc/NEWS | 4 ++-- PCbuild/get_externals.bat | 2 +- PCbuild/pyproject.props | 2 +- PCbuild/readme.txt | 2 +- 9 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -248,7 +248,8 @@ help sources can be specified. Non-default user setting are saved in a .idlerc directory in the user's home directory. Problems caused by bad user configuration files are solved by editing or deleting one or more of the - files in .idlerc. + files in .idlerc. On OS X, open the configuration dialog by selecting + Preferences in the application menu. Configure Extensions Open a configuration dialog for setting preferences for extensions diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -47,7 +47,7 @@ Module :mod:`doctest` Another test-support module with a very different flavor. - `Simple Smalltalk Testing: With Patterns `_ + `Simple Smalltalk Testing: With Patterns `_ Kent Beck's original paper on testing frameworks using the pattern shared by :mod:`unittest`. diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -129,7 +129,9 @@ Configure IDLE -- Open a configuration dialog. Fonts, indentation, keybindings, and color themes may be altered. Startup Preferences may be set, and additional Help - sources can be specified. + sources can be specified. On OS X, open the + configuration dialog by selecting Preferences + in the application menu. --- Code Context (toggle) -- Open a pane at the top of the edit window diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2a", - url="https://www.openssl.org/source/openssl-1.0.2a.tar.gz", - checksum='a06c547dac9044161a477211049f60ef', + name="OpenSSL 1.0.2c", + url="https://www.openssl.org/source/openssl-1.0.2c.tar.gz", + checksum='8c8d81a9ae7005276e486702edbcd4b6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -2,7 +2,7 @@ # Parent 25a9af415e8c3faf591c360d5f0e361d049b2b43 # openssl_sdk_makedepend.patch # -# using openssl 1.0.2a +# using openssl 1.0.2c # # - support building with an OS X SDK # - allow "make depend" to use compilers with names other than "gcc" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -342,8 +342,8 @@ - Issue #23445: pydebug builds now use "gcc -Og" where possible, to make the resulting executable faster. -- Issue #23686: Update OS X 10.5 installer and Windows builds to use - OpenSSL 1.0.2a. +- Issue #24432: Update Windows builds and OS X 10.5 installer to use OpenSSL + 1.0.2c. C API ----- diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ for %%e in ( bzip2-1.0.6 nasm-2.11.06 - openssl-1.0.2a + openssl-1.0.2c tcl-8.6.1.0 tk-8.6.1.0 tix-8.4.3.4 diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -20,7 +20,7 @@ $(externalsDir)\sqlite-3.8.3.1 $(externalsDir)\bzip2-1.0.6 $(externalsDir)\xz-5.0.5 - $(externalsDir)\openssl-1.0.2a + $(externalsDir)\openssl-1.0.2c $(externalsDir)\tcltk $(externalsDir)\tcltk64 $(tcltkDir)\lib\tcl86t.lib;$(tcltkDir)\lib\tk86t.lib diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -171,7 +171,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.2a of the OpenSSL secure sockets + Python wrapper for version 1.0.2c of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 05:54:14 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 03:54:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_merge_3=2E4?= Message-ID: <20150705035414.24661.88841@psf.io> https://hg.python.org/cpython/rev/74f55f8d8982 changeset: 96817:74f55f8d8982 branch: 3.5 parent: 96816:3c5af1b5a64b parent: 96815:725131a5f6cf user: Benjamin Peterson date: Sat Jul 04 22:53:37 2015 -0500 summary: merge 3.4 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 05:54:14 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 03:54:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNSk6?= =?utf-8?q?_merge_heads?= Message-ID: <20150705035414.18857.22655@psf.io> https://hg.python.org/cpython/rev/3c5af1b5a64b changeset: 96816:3c5af1b5a64b branch: 3.5 parent: 96813:6a7ee97cb0b1 parent: 96808:2dfdbbe0701b user: Benjamin Peterson date: Sat Jul 04 22:53:11 2015 -0500 summary: merge heads files: Doc/library/idle.rst | 3 +- Doc/library/unittest.rst | 2 +- Lib/idlelib/help.txt | 4 +- Mac/BuildScript/build-installer.py | 6 +- Mac/BuildScript/openssl_sdk_makedepend.patch | 2 +- Mac/BuildScript/resources/ReadMe.rtf | 69 +++++++++- Mac/BuildScript/scripts/postflight.ensurepip | 10 +- Mac/BuildScript/scripts/postflight.framework | 16 +- Misc/NEWS | 6 + PCbuild/get_externals.bat | 2 +- PCbuild/prepare_ssl.py | 1 + PCbuild/python.props | 2 +- PCbuild/python3dll.vcxproj | 4 +- PCbuild/readme.txt | 2 +- Tools/msi/build.bat | 16 +- Tools/msi/bundle/packagegroups/postinstall.wxs | 2 +- Tools/msi/msi.targets | 2 +- Tools/msi/pip/pip.wxs | 4 +- 18 files changed, 119 insertions(+), 34 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -248,7 +248,8 @@ help sources can be specified. Non-default user setting are saved in a .idlerc directory in the user's home directory. Problems caused by bad user configuration files are solved by editing or deleting one or more of the - files in .idlerc. + files in .idlerc. On OS X, open the configuration dialog by selecting + Preferences in the application menu. Configure Extensions Open a configuration dialog for setting preferences for extensions diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -47,7 +47,7 @@ Module :mod:`doctest` Another test-support module with a very different flavor. - `Simple Smalltalk Testing: With Patterns `_ + `Simple Smalltalk Testing: With Patterns `_ Kent Beck's original paper on testing frameworks using the pattern shared by :mod:`unittest`. diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -129,7 +129,9 @@ Configure IDLE -- Open a configuration dialog. Fonts, indentation, keybindings, and color themes may be altered. Startup Preferences may be set, and additional Help - sources can be specified. + sources can be specified. On OS X, open the + configuration dialog by selecting Preferences + in the application menu. --- Code Context (toggle) -- Open a pane at the top of the edit window diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2a", - url="https://www.openssl.org/source/openssl-1.0.2a.tar.gz", - checksum='a06c547dac9044161a477211049f60ef', + name="OpenSSL 1.0.2c", + url="https://www.openssl.org/source/openssl-1.0.2c.tar.gz", + checksum='8c8d81a9ae7005276e486702edbcd4b6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -2,7 +2,7 @@ # Parent 25a9af415e8c3faf591c360d5f0e361d049b2b43 # openssl_sdk_makedepend.patch # -# using openssl 1.0.2a +# using openssl 1.0.2c # # - support building with an OS X SDK # - allow "make depend" to use compilers with names other than "gcc" diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1347\cocoasubrtf570 +{\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} \margl1440\margr1440\vieww13380\viewh14600\viewkind0 @@ -24,7 +24,7 @@ \i0 variant. Unless you are installing to an 10.5 system or you need to build applications that can run on 10.5 systems, use the 10.6 variant if possible. There are some additional operating system functions that are supported starting with 10.6 and you may see better performance using 64-bit mode. By default, Python will automatically run in 64-bit mode if your system supports it. Also see \i Certificate verification and OpenSSL \i0 below. The Pythons installed by these installers are built with private copies of some third-party libraries not included with or newer than those in OS X itself. The list of these libraries varies by installer variant and is included at the end of the License.rtf file. -\b \ul \ulc0 \ +\b \ul \ \ Update your version of Tcl/Tk to use IDLE or other Tk applications \b0 \ulnone \ @@ -36,6 +36,71 @@ \i0 for this version of Python and of Mac OS X.\ \b \ul \ +Certificate verification and OpenSSL\ + +\b0 \ulnone \ +Python 3.5 includes a number of network security enhancements that were released in Python 3.4.3 and Python 2.7.10. {\field{\*\fldinst{HYPERLINK "https://www.python.org/dev/peps/pep-0476/"}}{\fldrslt PEP 476}} changes several standard library modules, like +\i httplib +\i0 , +\i urllib +\i0 , and +\i xmlrpclib +\i0 , to by default verify certificates presented by servers over secure (TLS) connections. The verification is performed by the OpenSSL libraries that Python is linked to. Prior to 3.4.3, both python.org installers dynamically linked with Apple-supplied OpenSSL libraries shipped with OS X. OS X provides a multiple level security framework that stores trust certificates in system and user keychains managed by the +\i Keychain Access +\i0 application and the +\i security +\i0 command line utility.\ +\ +For OS X 10.5, Apple provides +\i OpenSSL 0.9.7 +\i0 libraries. This version of Apple's OpenSSL +\b does not +\b0 use the certificates from the system security framework, even when used on newer versions of OS X. Instead it consults a traditional OpenSSL concatenated certificate file ( +\i cafile +\i0 ) or certificate directory ( +\i capath +\i0 ), located in +\f1 /System/Library/OpenSSL +\f0 . These directories are typically empty and not managed by OS X; you must manage them yourself or supply your own SSL contexts. OpenSSL 0.9.7 is obsolete by current security standards, lacking a number of important features found in later versions. Among the problems this causes is the inability to verify higher-security certificates now used by python.org services, including +\i t{\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi"}}{\fldrslt he Python Package Index, PyPI}} +\i0 . To solve this problem, the +\i 10.5+ 32-bit-only python.org variant +\i0 is linked with a private copy of +\i OpenSSL 1.0.2 +\i0 ; it consults the same default certificate directory, +\f1 /System/Library/OpenSSL +\f0 . As before, it is still necessary to manage certificates yourself when you use this Python variant and, with certificate verification now enabled by default, you may now need to take additional steps to ensure your Python programs have access to CA certificates you trust. If you use this Python variant to build standalone applications with third-party tools like {\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi/py2app/"}}{\fldrslt +\f1 py2app}}, you may now need to bundle CA certificates in them or otherwise supply non-default SSL contexts.\ +\ +For OS X 10.6+, Apple also provides +\i OpenSSL +\i0 +\i 0.9.8 libraries +\i0 . Apple's 0.9.8 version includes an important additional feature: if a certificate cannot be verified using the manually administered certificates in +\f1 /System/Library/OpenSSL +\f0 , the certificates managed by the system security framework In the user and system keychains are also consulted (using Apple private APIs). For this reason, the +\i 64-bit/32-bit 10.6+ python.org variant +\i0 continues to be dynamically linked with Apple's OpenSSL 0.9.8 since it was felt that the loss of the system-provided certificates and management tools outweighs the additional security features provided by newer versions of OpenSSL. This will likely change in future releases of the python.org installers as Apple has deprecated use of the system-supplied OpenSSL libraries. If you do need features from newer versions of OpenSSL, there are third-party OpenSSL wrapper packages available through +\i PyPI +\i0 .\ +\ +The bundled +\f1 pip +\f0 included with the Python 3.5 installers has its own default certificate store for verifying download connections.\ +\ + +\b \ul Other changes\ + +\b0 \ulnone \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural +\cf0 For other changes in this release, see the +\i What's new +\i0 section in the {\field{\*\fldinst{HYPERLINK "https://www.python.org/doc/"}}{\fldrslt Documentation Set}} for this release and its +\i Release Notes +\i0 link at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural + +\b \cf0 \ul \ Python 3 and Python 2 Co-existence\ \b0 \ulnone \ diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip --- a/Mac/BuildScript/scripts/postflight.ensurepip +++ b/Mac/BuildScript/scripts/postflight.ensurepip @@ -10,15 +10,15 @@ umask 022 -"${FWK}/bin/python${PYVER}" -m ensurepip --upgrade +"${FWK}/bin/python${PYVER}" -E -s -m ensurepip --upgrade -"${FWK}/bin/python${PYVER}" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python${PYVER}" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -"${FWK}/bin/python${PYVER}" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python${PYVER}" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" diff --git a/Mac/BuildScript/scripts/postflight.framework b/Mac/BuildScript/scripts/postflight.framework --- a/Mac/BuildScript/scripts/postflight.framework +++ b/Mac/BuildScript/scripts/postflight.framework @@ -6,23 +6,23 @@ PYVER="@PYVER@" FWK="/Library/Frameworks/Python.framework/Versions/@PYVER@" -"${FWK}/bin/python at PYVER@" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ "${FWK}/lib/python${PYVER}" -"${FWK}/bin/python at PYVER@" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ "${FWK}/lib/python${PYVER}" -"${FWK}/bin/python at PYVER@" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -"${FWK}/bin/python at PYVER@" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -102,6 +102,12 @@ - Issue #24351: Clarify what is meant by "identifier" in the context of string.Template instances. +Build +----- + +- Issue #24432: Update Windows builds and OS X 10.5 installer to use OpenSSL + 1.0.2c. + What's New in Python 3.5.0 beta 2? ================================== diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ for %%e in ( bzip2-1.0.6 nasm-2.11.06 - openssl-1.0.2a + openssl-1.0.2c tcl-core-8.6.4.1 tk-8.6.4.1 tix-8.4.3.4 diff --git a/PCbuild/prepare_ssl.py b/PCbuild/prepare_ssl.py --- a/PCbuild/prepare_ssl.py +++ b/PCbuild/prepare_ssl.py @@ -1,3 +1,4 @@ +#! /usr/bin/env python3 # Script for preparing OpenSSL for building on Windows. # Uses Perl to create nmake makefiles and otherwise prepare the way # for building on 32 or 64 bit platforms. diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -34,7 +34,7 @@ $(ExternalsDir)sqlite-3.8.3.1\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.0.5\ - $(ExternalsDir)openssl-1.0.2a\ + $(ExternalsDir)openssl-1.0.2c\ $(ExternalsDir)\nasm-2.11.06\ diff --git a/PCbuild/python3dll.vcxproj b/PCbuild/python3dll.vcxproj --- a/PCbuild/python3dll.vcxproj +++ b/PCbuild/python3dll.vcxproj @@ -109,7 +109,7 @@ - + @@ -132,7 +132,7 @@ <_Lines Include="@(_Symbols->'%(Symbol)')" /> - + diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -197,7 +197,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.1j of the OpenSSL secure sockets + Python wrapper for version 1.0.2c of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ diff --git a/Tools/msi/build.bat b/Tools/msi/build.bat --- a/Tools/msi/build.bat +++ b/Tools/msi/build.bat @@ -8,9 +8,10 @@ set BUILDDOC= :CheckOpts -if '%1'=='-x86' (set BUILDX86=1) && shift && goto CheckOpts -if '%1'=='-x64' (set BUILDX64=1) && shift && goto CheckOpts -if '%1'=='--doc' (set BUILDDOC=1) && shift && goto CheckOpts +if "%1" EQU "-h" goto Help +if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts +if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts +if "%1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) @@ -44,3 +45,12 @@ msbuild "%D%bundle\snapshot.wixproj" /p:Platform=x64 if errorlevel 1 goto :eof ) + +exit /B 0 + +:Help +echo build.bat [-x86] [-x64] [--doc] [-h] +echo. +echo -x86 Build x86 installers +echo -x64 Build x64 installers +echo --doc Build CHM documentation diff --git a/Tools/msi/bundle/packagegroups/postinstall.wxs b/Tools/msi/bundle/packagegroups/postinstall.wxs --- a/Tools/msi/bundle/packagegroups/postinstall.wxs +++ b/Tools/msi/bundle/packagegroups/postinstall.wxs @@ -36,7 +36,7 @@ - + - + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) diff --git a/Tools/msi/pip/pip.wxs b/Tools/msi/pip/pip.wxs --- a/Tools/msi/pip/pip.wxs +++ b/Tools/msi/pip/pip.wxs @@ -27,8 +27,8 @@ - - + + (&DefaultFeature=3) AND NOT (!DefaultFeature=3) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 05:54:19 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 03:54:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy41?= Message-ID: <20150705035419.26537.976@psf.io> https://hg.python.org/cpython/rev/fdad98dde75a changeset: 96819:fdad98dde75a parent: 96818:f4e6e96adcdf parent: 96817:74f55f8d8982 user: Benjamin Peterson date: Sat Jul 04 22:53:55 2015 -0500 summary: merge 3.5 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 05:54:19 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 03:54:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge_heads?= Message-ID: <20150705035419.87143.41096@psf.io> https://hg.python.org/cpython/rev/f4e6e96adcdf changeset: 96818:f4e6e96adcdf parent: 96814:88814ddd5e9e parent: 96810:7900983373f0 user: Benjamin Peterson date: Sat Jul 04 22:53:45 2015 -0500 summary: merge heads files: Doc/library/idle.rst | 3 +- Doc/library/unittest.rst | 2 +- Include/unicodeobject.h | 4 + Lib/idlelib/help.txt | 4 +- Mac/BuildScript/build-installer.py | 6 +- Mac/BuildScript/openssl_sdk_makedepend.patch | 2 +- Mac/BuildScript/resources/ReadMe.rtf | 69 ++++- Mac/BuildScript/scripts/postflight.ensurepip | 10 +- Mac/BuildScript/scripts/postflight.framework | 16 +- Misc/NEWS | 6 + Objects/setobject.c | 140 ++++----- Objects/unicodeobject.c | 7 + PCbuild/get_externals.bat | 2 +- PCbuild/prepare_ssl.py | 1 + PCbuild/python.props | 2 +- PCbuild/python3dll.vcxproj | 4 +- PCbuild/readme.txt | 2 +- Tools/msi/build.bat | 16 +- Tools/msi/bundle/packagegroups/postinstall.wxs | 2 +- Tools/msi/msi.targets | 2 +- Tools/msi/pip/pip.wxs | 4 +- 21 files changed, 190 insertions(+), 114 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -248,7 +248,8 @@ help sources can be specified. Non-default user setting are saved in a .idlerc directory in the user's home directory. Problems caused by bad user configuration files are solved by editing or deleting one or more of the - files in .idlerc. + files in .idlerc. On OS X, open the configuration dialog by selecting + Preferences in the application menu. Configure Extensions Open a configuration dialog for setting preferences for extensions diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -47,7 +47,7 @@ Module :mod:`doctest` Another test-support module with a very different flavor. - `Simple Smalltalk Testing: With Patterns `_ + `Simple Smalltalk Testing: With Patterns `_ Kent Beck's original paper on testing frameworks using the pattern shared by :mod:`unittest`. diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -2261,6 +2261,10 @@ /* Clear all static strings. */ PyAPI_FUNC(void) _PyUnicode_ClearStaticStrings(void); +/* Fast equality check when the inputs are known to be exact unicode types + and where the hash values are equal (i.e. a very probable match) */ +PyAPI_FUNC(int) _PyUnicode_EQ(PyObject *, PyObject *); + #ifdef __cplusplus } #endif diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -129,7 +129,9 @@ Configure IDLE -- Open a configuration dialog. Fonts, indentation, keybindings, and color themes may be altered. Startup Preferences may be set, and additional Help - sources can be specified. + sources can be specified. On OS X, open the + configuration dialog by selecting Preferences + in the application menu. --- Code Context (toggle) -- Open a pane at the top of the edit window diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2a", - url="https://www.openssl.org/source/openssl-1.0.2a.tar.gz", - checksum='a06c547dac9044161a477211049f60ef', + name="OpenSSL 1.0.2c", + url="https://www.openssl.org/source/openssl-1.0.2c.tar.gz", + checksum='8c8d81a9ae7005276e486702edbcd4b6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -2,7 +2,7 @@ # Parent 25a9af415e8c3faf591c360d5f0e361d049b2b43 # openssl_sdk_makedepend.patch # -# using openssl 1.0.2a +# using openssl 1.0.2c # # - support building with an OS X SDK # - allow "make depend" to use compilers with names other than "gcc" diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1347\cocoasubrtf570 +{\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} \margl1440\margr1440\vieww13380\viewh14600\viewkind0 @@ -24,7 +24,7 @@ \i0 variant. Unless you are installing to an 10.5 system or you need to build applications that can run on 10.5 systems, use the 10.6 variant if possible. There are some additional operating system functions that are supported starting with 10.6 and you may see better performance using 64-bit mode. By default, Python will automatically run in 64-bit mode if your system supports it. Also see \i Certificate verification and OpenSSL \i0 below. The Pythons installed by these installers are built with private copies of some third-party libraries not included with or newer than those in OS X itself. The list of these libraries varies by installer variant and is included at the end of the License.rtf file. -\b \ul \ulc0 \ +\b \ul \ \ Update your version of Tcl/Tk to use IDLE or other Tk applications \b0 \ulnone \ @@ -36,6 +36,71 @@ \i0 for this version of Python and of Mac OS X.\ \b \ul \ +Certificate verification and OpenSSL\ + +\b0 \ulnone \ +Python 3.5 includes a number of network security enhancements that were released in Python 3.4.3 and Python 2.7.10. {\field{\*\fldinst{HYPERLINK "https://www.python.org/dev/peps/pep-0476/"}}{\fldrslt PEP 476}} changes several standard library modules, like +\i httplib +\i0 , +\i urllib +\i0 , and +\i xmlrpclib +\i0 , to by default verify certificates presented by servers over secure (TLS) connections. The verification is performed by the OpenSSL libraries that Python is linked to. Prior to 3.4.3, both python.org installers dynamically linked with Apple-supplied OpenSSL libraries shipped with OS X. OS X provides a multiple level security framework that stores trust certificates in system and user keychains managed by the +\i Keychain Access +\i0 application and the +\i security +\i0 command line utility.\ +\ +For OS X 10.5, Apple provides +\i OpenSSL 0.9.7 +\i0 libraries. This version of Apple's OpenSSL +\b does not +\b0 use the certificates from the system security framework, even when used on newer versions of OS X. Instead it consults a traditional OpenSSL concatenated certificate file ( +\i cafile +\i0 ) or certificate directory ( +\i capath +\i0 ), located in +\f1 /System/Library/OpenSSL +\f0 . These directories are typically empty and not managed by OS X; you must manage them yourself or supply your own SSL contexts. OpenSSL 0.9.7 is obsolete by current security standards, lacking a number of important features found in later versions. Among the problems this causes is the inability to verify higher-security certificates now used by python.org services, including +\i t{\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi"}}{\fldrslt he Python Package Index, PyPI}} +\i0 . To solve this problem, the +\i 10.5+ 32-bit-only python.org variant +\i0 is linked with a private copy of +\i OpenSSL 1.0.2 +\i0 ; it consults the same default certificate directory, +\f1 /System/Library/OpenSSL +\f0 . As before, it is still necessary to manage certificates yourself when you use this Python variant and, with certificate verification now enabled by default, you may now need to take additional steps to ensure your Python programs have access to CA certificates you trust. If you use this Python variant to build standalone applications with third-party tools like {\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi/py2app/"}}{\fldrslt +\f1 py2app}}, you may now need to bundle CA certificates in them or otherwise supply non-default SSL contexts.\ +\ +For OS X 10.6+, Apple also provides +\i OpenSSL +\i0 +\i 0.9.8 libraries +\i0 . Apple's 0.9.8 version includes an important additional feature: if a certificate cannot be verified using the manually administered certificates in +\f1 /System/Library/OpenSSL +\f0 , the certificates managed by the system security framework In the user and system keychains are also consulted (using Apple private APIs). For this reason, the +\i 64-bit/32-bit 10.6+ python.org variant +\i0 continues to be dynamically linked with Apple's OpenSSL 0.9.8 since it was felt that the loss of the system-provided certificates and management tools outweighs the additional security features provided by newer versions of OpenSSL. This will likely change in future releases of the python.org installers as Apple has deprecated use of the system-supplied OpenSSL libraries. If you do need features from newer versions of OpenSSL, there are third-party OpenSSL wrapper packages available through +\i PyPI +\i0 .\ +\ +The bundled +\f1 pip +\f0 included with the Python 3.5 installers has its own default certificate store for verifying download connections.\ +\ + +\b \ul Other changes\ + +\b0 \ulnone \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural +\cf0 For other changes in this release, see the +\i What's new +\i0 section in the {\field{\*\fldinst{HYPERLINK "https://www.python.org/doc/"}}{\fldrslt Documentation Set}} for this release and its +\i Release Notes +\i0 link at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural + +\b \cf0 \ul \ Python 3 and Python 2 Co-existence\ \b0 \ulnone \ diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip --- a/Mac/BuildScript/scripts/postflight.ensurepip +++ b/Mac/BuildScript/scripts/postflight.ensurepip @@ -10,15 +10,15 @@ umask 022 -"${FWK}/bin/python${PYVER}" -m ensurepip --upgrade +"${FWK}/bin/python${PYVER}" -E -s -m ensurepip --upgrade -"${FWK}/bin/python${PYVER}" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python${PYVER}" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -"${FWK}/bin/python${PYVER}" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python${PYVER}" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" diff --git a/Mac/BuildScript/scripts/postflight.framework b/Mac/BuildScript/scripts/postflight.framework --- a/Mac/BuildScript/scripts/postflight.framework +++ b/Mac/BuildScript/scripts/postflight.framework @@ -6,23 +6,23 @@ PYVER="@PYVER@" FWK="/Library/Frameworks/Python.framework/Versions/@PYVER@" -"${FWK}/bin/python at PYVER@" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ "${FWK}/lib/python${PYVER}" -"${FWK}/bin/python at PYVER@" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ "${FWK}/lib/python${PYVER}" -"${FWK}/bin/python at PYVER@" -Wi \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" -"${FWK}/bin/python at PYVER@" -Wi -O \ - "${FWK}/lib/python${PYVER}/compileall.py" \ +"${FWK}/bin/python at PYVER@" -E -s -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ -f -x badsyntax \ "${FWK}/lib/python${PYVER}/site-packages" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -118,6 +118,12 @@ - Issue #24351: Clarify what is meant by "identifier" in the context of string.Template instances. +Build +----- + +- Issue #24432: Update Windows builds and OS X 10.5 installer to use OpenSSL + 1.0.2c. + What's New in Python 3.5.0 beta 2? ================================== diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -29,7 +29,6 @@ #include "Python.h" #include "structmember.h" -#include "stringlib/eq.h" /* Object used as dummy key to fill deleted entries */ static PyObject _dummy_struct; @@ -74,7 +73,7 @@ return entry; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) + && _PyUnicode_EQ(startkey, key)) return entry; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -100,7 +99,7 @@ return entry; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) + && _PyUnicode_EQ(startkey, key)) return entry; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -125,6 +124,8 @@ } } +static int set_table_resize(PySetObject *, Py_ssize_t); + static int set_insert_key(PySetObject *so, PyObject *key, Py_hash_t hash) { @@ -139,7 +140,7 @@ entry = &table[i]; if (entry->key == NULL) - goto found_null_first; + goto found_unused; freeslot = NULL; perturb = hash; @@ -153,7 +154,7 @@ goto found_active; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) + && _PyUnicode_EQ(startkey, key)) goto found_active; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -173,7 +174,7 @@ for (j = 0 ; j < LINEAR_PROBES ; j++) { entry++; if (entry->hash == 0 && entry->key == NULL) - goto found_null; + goto found_unused_or_dummy; if (entry->hash == hash) { PyObject *startkey = entry->key; assert(startkey != dummy); @@ -181,7 +182,7 @@ goto found_active; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) + && _PyUnicode_EQ(startkey, key)) goto found_active; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -204,30 +205,27 @@ entry = &table[i]; if (entry->key == NULL) - goto found_null; + goto found_unused_or_dummy; } - found_null_first: + found_unused_or_dummy: + if (freeslot == NULL) + goto found_unused; + Py_INCREF(key); + so->used++; + freeslot->key = key; + freeslot->hash = hash; + return 0; + + found_unused: Py_INCREF(key); so->fill++; so->used++; entry->key = key; entry->hash = hash; - return 0; - - found_null: - Py_INCREF(key); - if (freeslot == NULL) { - /* UNUSED */ - so->fill++; - } else { - /* DUMMY */ - entry = freeslot; - } - so->used++; - entry->key = key; - entry->hash = hash; - return 0; + if ((size_t)so->fill*3 < mask*2) + return 0; + return set_table_resize(so, so->used); found_active: return 0; @@ -291,6 +289,7 @@ setentry small_copy[PySet_MINSIZE]; assert(minused >= 0); + minused = (minused > 50000) ? minused * 2 : minused * 4; /* Find the smallest table size > minused. */ /* XXX speed-up with intrinsics */ @@ -366,28 +365,15 @@ return 0; } -/* CAUTION: set_add_key/entry() must guarantee it won't resize the table */ - static int set_add_entry(PySetObject *so, setentry *entry) { - Py_ssize_t n_used; - PyObject *key = entry->key; - Py_hash_t hash = entry->hash; - - assert(so->fill <= so->mask); /* at least one empty slot */ - n_used = so->used; - if (set_insert_key(so, key, hash)) - return -1; - if (!(so->used > n_used && so->fill*3 >= (so->mask+1)*2)) - return 0; - return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); + return set_insert_key(so, entry->key, entry->hash); } static int set_add_key(PySetObject *so, PyObject *key) { - setentry entry; Py_hash_t hash; if (!PyUnicode_CheckExact(key) || @@ -396,9 +382,7 @@ if (hash == -1) return -1; } - entry.key = key; - entry.hash = hash; - return set_add_entry(so, &entry); + return set_insert_key(so, key, hash); } #define DISCARD_NOTFOUND 0 @@ -631,8 +615,8 @@ * incrementally resizing as we insert new keys. Expect * that there will be no (or few) overlapping keys. */ - if ((so->fill + other->used)*3 >= (so->mask+1)*2) { - if (set_table_resize(so, (so->used + other->used)*2) != 0) + if ((so->fill + other->used)*3 >= so->mask*2) { + if (set_table_resize(so, so->used + other->used) != 0) return -1; } so_entry = so->table; @@ -694,7 +678,7 @@ static int set_contains_key(PySetObject *so, PyObject *key) { - setentry entry; + setentry *entry; Py_hash_t hash; if (!PyUnicode_CheckExact(key) || @@ -703,9 +687,10 @@ if (hash == -1) return -1; } - entry.key = key; - entry.hash = hash; - return set_contains_entry(so, &entry); + entry = set_lookkey(so, key, hash); + if (entry == NULL) + return -1; + return entry->key != NULL; } static PyObject * @@ -977,18 +962,14 @@ * incrementally resizing as we insert new keys. Expect * that there will be no (or few) overlapping keys. */ - if (dictsize == -1) + if (dictsize < 0) return -1; - if ((so->fill + dictsize)*3 >= (so->mask+1)*2) { - if (set_table_resize(so, (so->used + dictsize)*2) != 0) + if ((so->fill + dictsize)*3 >= so->mask*2) { + if (set_table_resize(so, so->used + dictsize) != 0) return -1; } while (_PyDict_Next(other, &pos, &key, &value, &hash)) { - setentry an_entry; - - an_entry.hash = hash; - an_entry.key = key; - if (set_add_entry(so, &an_entry)) + if (set_insert_key(so, key, hash)) return -1; } return 0; @@ -1288,7 +1269,7 @@ while (set_next((PySetObject *)other, &pos, &entry)) { int rv = set_contains_entry(so, entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(result); return NULL; } @@ -1322,7 +1303,7 @@ entry.hash = hash; entry.key = key; rv = set_contains_entry(so, &entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(it); Py_DECREF(result); Py_DECREF(key); @@ -1449,7 +1430,7 @@ } while (set_next((PySetObject *)other, &pos, &entry)) { int rv = set_contains_entry(so, entry); - if (rv == -1) + if (rv < 0) return NULL; if (rv) Py_RETURN_FALSE; @@ -1475,7 +1456,7 @@ entry.key = key; rv = set_contains_entry(so, &entry); Py_DECREF(key); - if (rv == -1) { + if (rv < 0) { Py_DECREF(it); return NULL; } @@ -1504,7 +1485,7 @@ Py_ssize_t pos = 0; while (set_next((PySetObject *)other, &pos, &entry)) - if (set_discard_entry(so, entry) == -1) + if (set_discard_entry(so, entry) < 0) return -1; } else { PyObject *key, *it; @@ -1513,7 +1494,7 @@ return -1; while ((key = PyIter_Next(it)) != NULL) { - if (set_discard_key(so, key) == -1) { + if (set_discard_key(so, key) < 0) { Py_DECREF(it); Py_DECREF(key); return -1; @@ -1524,10 +1505,10 @@ if (PyErr_Occurred()) return -1; } - /* If more than 1/5 are dummies, then resize them away. */ - if ((so->fill - so->used) * 5 < so->mask) + /* If more than 1/4th are dummies, then resize them away. */ + if ((size_t)(so->fill - so->used) <= (size_t)so->mask / 4) return 0; - return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); + return set_table_resize(so, so->used); } static PyObject * @@ -1554,7 +1535,7 @@ result = set_copy(so); if (result == NULL) return NULL; - if (set_difference_update_internal((PySetObject *) result, other) != -1) + if (set_difference_update_internal((PySetObject *) result, other) == 0) return result; Py_DECREF(result); return NULL; @@ -1583,17 +1564,16 @@ if (PyDict_CheckExact(other)) { while (set_next(so, &pos, &entry)) { - setentry entrycopy; + PyObject *key = entry->key; + Py_hash_t hash = entry->hash; int rv; - entrycopy.hash = entry->hash; - entrycopy.key = entry->key; - rv = _PyDict_Contains(other, entry->key, entry->hash); + rv = _PyDict_Contains(other, key, hash); if (rv < 0) { Py_DECREF(result); return NULL; } if (!rv) { - if (set_add_entry((PySetObject *)result, &entrycopy)) { + if (set_insert_key((PySetObject *)result, key, hash)) { Py_DECREF(result); return NULL; } @@ -1605,7 +1585,7 @@ /* Iterate over so, checking for common elements in other. */ while (set_next(so, &pos, &entry)) { int rv = set_contains_entry((PySetObject *)other, entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(result); return NULL; } @@ -1689,7 +1669,7 @@ an_entry.key = key; rv = set_discard_entry(so, &an_entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(key); return NULL; } @@ -1715,7 +1695,7 @@ while (set_next(otherset, &pos, &entry)) { int rv = set_discard_entry(so, entry); - if (rv == -1) { + if (rv < 0) { Py_DECREF(otherset); return NULL; } @@ -1797,7 +1777,7 @@ while (set_next(so, &pos, &entry)) { int rv = set_contains_entry((PySetObject *)other, entry); - if (rv == -1) + if (rv < 0) return NULL; if (!rv) Py_RETURN_FALSE; @@ -1888,7 +1868,7 @@ int rv; rv = set_contains_key(so, key); - if (rv == -1) { + if (rv < 0) { if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) return -1; PyErr_Clear(); @@ -1907,7 +1887,7 @@ long result; result = set_contains(so, key); - if (result == -1) + if (result < 0) return NULL; return PyBool_FromLong(result); } @@ -1921,7 +1901,7 @@ int rv; rv = set_discard_key(so, key); - if (rv == -1) { + if (rv < 0) { if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) return NULL; PyErr_Clear(); @@ -1930,7 +1910,7 @@ return NULL; rv = set_discard_key(so, tmpkey); Py_DECREF(tmpkey); - if (rv == -1) + if (rv < 0) return NULL; } @@ -1953,7 +1933,7 @@ int rv; rv = set_discard_key(so, key); - if (rv == -1) { + if (rv < 0) { if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) return NULL; PyErr_Clear(); @@ -1962,7 +1942,7 @@ return NULL; rv = set_discard_key(so, tmpkey); Py_DECREF(tmpkey); - if (rv == -1) + if (rv < 0) return NULL; } Py_RETURN_NONE; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -42,6 +42,7 @@ #include "Python.h" #include "ucnhash.h" #include "bytes_methods.h" +#include "stringlib/eq.h" #ifdef MS_WINDOWS #include @@ -10887,6 +10888,12 @@ } int +_PyUnicode_EQ(PyObject *aa, PyObject *bb) +{ + return unicode_eq(aa, bb); +} + +int PyUnicode_Contains(PyObject *container, PyObject *element) { PyObject *str, *sub; diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ for %%e in ( bzip2-1.0.6 nasm-2.11.06 - openssl-1.0.2a + openssl-1.0.2c tcl-core-8.6.4.1 tk-8.6.4.1 tix-8.4.3.4 diff --git a/PCbuild/prepare_ssl.py b/PCbuild/prepare_ssl.py --- a/PCbuild/prepare_ssl.py +++ b/PCbuild/prepare_ssl.py @@ -1,3 +1,4 @@ +#! /usr/bin/env python3 # Script for preparing OpenSSL for building on Windows. # Uses Perl to create nmake makefiles and otherwise prepare the way # for building on 32 or 64 bit platforms. diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -34,7 +34,7 @@ $(ExternalsDir)sqlite-3.8.3.1\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.0.5\ - $(ExternalsDir)openssl-1.0.2a\ + $(ExternalsDir)openssl-1.0.2c\ $(ExternalsDir)\nasm-2.11.06\ diff --git a/PCbuild/python3dll.vcxproj b/PCbuild/python3dll.vcxproj --- a/PCbuild/python3dll.vcxproj +++ b/PCbuild/python3dll.vcxproj @@ -109,7 +109,7 @@ - + @@ -132,7 +132,7 @@ <_Lines Include="@(_Symbols->'%(Symbol)')" /> - + diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -197,7 +197,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.1j of the OpenSSL secure sockets + Python wrapper for version 1.0.2c of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ diff --git a/Tools/msi/build.bat b/Tools/msi/build.bat --- a/Tools/msi/build.bat +++ b/Tools/msi/build.bat @@ -8,9 +8,10 @@ set BUILDDOC= :CheckOpts -if '%1'=='-x86' (set BUILDX86=1) && shift && goto CheckOpts -if '%1'=='-x64' (set BUILDX64=1) && shift && goto CheckOpts -if '%1'=='--doc' (set BUILDDOC=1) && shift && goto CheckOpts +if "%1" EQU "-h" goto Help +if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts +if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts +if "%1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) @@ -44,3 +45,12 @@ msbuild "%D%bundle\snapshot.wixproj" /p:Platform=x64 if errorlevel 1 goto :eof ) + +exit /B 0 + +:Help +echo build.bat [-x86] [-x64] [--doc] [-h] +echo. +echo -x86 Build x86 installers +echo -x64 Build x64 installers +echo --doc Build CHM documentation diff --git a/Tools/msi/bundle/packagegroups/postinstall.wxs b/Tools/msi/bundle/packagegroups/postinstall.wxs --- a/Tools/msi/bundle/packagegroups/postinstall.wxs +++ b/Tools/msi/bundle/packagegroups/postinstall.wxs @@ -36,7 +36,7 @@ - + - + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) diff --git a/Tools/msi/pip/pip.wxs b/Tools/msi/pip/pip.wxs --- a/Tools/msi/pip/pip.wxs +++ b/Tools/msi/pip/pip.wxs @@ -27,8 +27,8 @@ - - + + (&DefaultFeature=3) AND NOT (!DefaultFeature=3) -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 5 10:46:16 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 05 Jul 2015 08:46:16 +0000 Subject: [Python-checkins] Daily reference leaks (fdad98dde75a): sum=4 Message-ID: <20150705084616.32451.37194@psf.io> results for fdad98dde75a on branch "default" -------------------------------------------- test_functools leaked [0, 2, 2] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflog68XswJ', '--timeout', '7200'] From python-checkins at python.org Sun Jul 5 16:43:54 2015 From: python-checkins at python.org (steve.dower) Date: Sun, 05 Jul 2015 14:43:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Fixes_rebuild_?= =?utf-8?q?of_strings_for_Windows_installer=2E?= Message-ID: <20150705144354.7863.9433@psf.io> https://hg.python.org/cpython/rev/60b84c6751d3 changeset: 96820:60b84c6751d3 branch: 3.5 parent: 96817:74f55f8d8982 user: Steve Dower date: Sun Jul 05 07:24:17 2015 -0700 summary: Fixes rebuild of strings for Windows installer. files: Tools/msi/msi.targets | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets --- a/Tools/msi/msi.targets +++ b/Tools/msi/msi.targets @@ -24,7 +24,7 @@ - + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 16:43:54 2015 From: python-checkins at python.org (steve.dower) Date: Sun, 05 Jul 2015 14:43:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Fixes_rebuild_of_strings_for_Windows_installer=2E?= Message-ID: <20150705144354.19972.68776@psf.io> https://hg.python.org/cpython/rev/1cb6f2031970 changeset: 96821:1cb6f2031970 parent: 96819:fdad98dde75a parent: 96820:60b84c6751d3 user: Steve Dower date: Sun Jul 05 07:24:47 2015 -0700 summary: Fixes rebuild of strings for Windows installer. files: Tools/msi/msi.targets | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets --- a/Tools/msi/msi.targets +++ b/Tools/msi/msi.targets @@ -24,7 +24,7 @@ - + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 17:39:27 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 15:39:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_add_news_secti?= =?utf-8?q?on_for_next_beta?= Message-ID: <20150705153927.66728.25606@psf.io> https://hg.python.org/cpython/rev/9e428956245a changeset: 96822:9e428956245a branch: 3.5 parent: 96817:74f55f8d8982 user: Benjamin Peterson date: Sun Jul 05 10:37:00 2015 -0500 summary: add news section for next beta files: Misc/NEWS | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,18 @@ Python News +++++++++++ +What's New in Python 3.5.0 beta 4? +================================== + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.5.0 beta 3? ================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 17:39:27 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 15:39:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_set_items_in_d?= =?utf-8?q?ict_displays_from_left_to_right_=28closes_=2324569=29?= Message-ID: <20150705153927.99345.95665@psf.io> https://hg.python.org/cpython/rev/a4df0fe62b46 changeset: 96823:a4df0fe62b46 branch: 3.5 user: Benjamin Peterson date: Sun Jul 05 10:37:25 2015 -0500 summary: set items in dict displays from left to right (closes #24569) files: Lib/test/test_unpack_ex.py | 3 +++ Misc/NEWS | 2 ++ Python/ceval.c | 15 +++++++++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py --- a/Lib/test/test_unpack_ex.py +++ b/Lib/test/test_unpack_ex.py @@ -128,6 +128,9 @@ ... for i in range(1000)) + "}")) 1000 + >>> {0:1, **{0:2}, 0:3, 0:4} + {0: 4} + List comprehension element unpacking >>> a, b, c = [0, 1, 2], 3, 4 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #24569: Make PEP 448 dictionary evaluation more consistent. + Library ------- diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2561,22 +2561,25 @@ } TARGET(BUILD_MAP) { + int i; PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg); if (map == NULL) goto error; - while (--oparg >= 0) { + for (i = oparg; i > 0; i--) { int err; - PyObject *value = TOP(); - PyObject *key = SECOND(); - STACKADJ(-2); + PyObject *key = PEEK(2*i); + PyObject *value = PEEK(2*i - 1); err = PyDict_SetItem(map, key, value); - Py_DECREF(value); - Py_DECREF(key); if (err != 0) { Py_DECREF(map); goto error; } } + + while (oparg--) { + Py_DECREF(POP()); + Py_DECREF(POP()); + } PUSH(map); DISPATCH(); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 17:39:27 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 15:39:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy41ICgjMjQ1Njkp?= Message-ID: <20150705153927.3167.38063@psf.io> https://hg.python.org/cpython/rev/75852d90c225 changeset: 96824:75852d90c225 parent: 96819:fdad98dde75a parent: 96823:a4df0fe62b46 user: Benjamin Peterson date: Sun Jul 05 10:38:05 2015 -0500 summary: merge 3.5 (#24569) files: Lib/test/test_unpack_ex.py | 3 +++ Misc/NEWS | 14 ++++++++++++++ Python/ceval.c | 15 +++++++++------ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py --- a/Lib/test/test_unpack_ex.py +++ b/Lib/test/test_unpack_ex.py @@ -128,6 +128,9 @@ ... for i in range(1000)) + "}")) 1000 + >>> {0:1, **{0:2}, 0:3, 0:4} + {0: 4} + List comprehension element unpacking >>> a, b, c = [0, 1, 2], 3, 4 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,20 @@ now can't be disabled at compile time. +What's New in Python 3.5.0 beta 4? +================================== + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +- Issue #24569: Make PEP 448 dictionary evaluation more consistent. + +Library +------- + + What's New in Python 3.5.0 beta 3? ================================== diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2561,22 +2561,25 @@ } TARGET(BUILD_MAP) { + int i; PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg); if (map == NULL) goto error; - while (--oparg >= 0) { + for (i = oparg; i > 0; i--) { int err; - PyObject *value = TOP(); - PyObject *key = SECOND(); - STACKADJ(-2); + PyObject *key = PEEK(2*i); + PyObject *value = PEEK(2*i - 1); err = PyDict_SetItem(map, key, value); - Py_DECREF(value); - Py_DECREF(key); if (err != 0) { Py_DECREF(map); goto error; } } + + while (oparg--) { + Py_DECREF(POP()); + Py_DECREF(POP()); + } PUSH(map); DISPATCH(); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 17:39:27 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 15:39:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNSk6?= =?utf-8?q?_merge_heads?= Message-ID: <20150705153927.9956.69889@psf.io> https://hg.python.org/cpython/rev/4623c0edc5e6 changeset: 96825:4623c0edc5e6 branch: 3.5 parent: 96823:a4df0fe62b46 parent: 96820:60b84c6751d3 user: Benjamin Peterson date: Sun Jul 05 10:39:13 2015 -0500 summary: merge heads files: Tools/msi/msi.targets | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets --- a/Tools/msi/msi.targets +++ b/Tools/msi/msi.targets @@ -24,7 +24,7 @@ - + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 17:39:28 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 15:39:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge_heads?= Message-ID: <20150705153927.10165.44055@psf.io> https://hg.python.org/cpython/rev/0023993b93ea changeset: 96826:0023993b93ea parent: 96824:75852d90c225 parent: 96821:1cb6f2031970 user: Benjamin Peterson date: Sun Jul 05 10:39:18 2015 -0500 summary: merge heads files: Tools/msi/msi.targets | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets --- a/Tools/msi/msi.targets +++ b/Tools/msi/msi.targets @@ -24,7 +24,7 @@ - + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 17:39:28 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 15:39:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy41?= Message-ID: <20150705153928.27420.83938@psf.io> https://hg.python.org/cpython/rev/834fcda98ed9 changeset: 96827:834fcda98ed9 parent: 96826:0023993b93ea parent: 96825:4623c0edc5e6 user: Benjamin Peterson date: Sun Jul 05 10:39:22 2015 -0500 summary: merge 3.5 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 17:39:55 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 15:39:55 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogJ2ZyZWUtYWZ0ZXIt?= =?utf-8?q?use=27_is_not_a_bug_=3A=29_=28closes_=2324568=29?= Message-ID: <20150705153955.20181.56112@psf.io> https://hg.python.org/cpython/rev/5097c91cdc2d changeset: 96828:5097c91cdc2d branch: 2.7 parent: 96692:4f48b1e982ca user: Benjamin Peterson date: Sun Jul 05 10:39:47 2015 -0500 summary: 'free-after-use' is not a bug :) (closes #24568) files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -138,7 +138,7 @@ - Issue #23008: Fixed resolving attributes with boolean value is False in pydoc. -- Issues #24099, #24100, and #24101: Fix free-after-use bug in heapq's siftup +- Issues #24099, #24100, and #24101: Fix use-after-use bug in heapq's siftup and siftdown functions. - Backport collections.deque fixes from Python 3.5. Prevents reentrant badness -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 17:40:01 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 05 Jul 2015 15:40:01 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_Merge_heads?= Message-ID: <20150705154001.17196.13439@psf.io> https://hg.python.org/cpython/rev/756876e059cb changeset: 96829:756876e059cb branch: 2.7 parent: 96828:5097c91cdc2d parent: 96806:64b42ec6ef42 user: Benjamin Peterson date: Sun Jul 05 10:39:53 2015 -0500 summary: Merge heads files: Doc/library/idle.rst | 3 +- Doc/library/unittest.rst | 2 +- Doc/library/urllib.rst | 2 +- Lib/ensurepip/__init__.py | 4 +- Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl | Bin Lib/idlelib/help.txt | 7 +- Lib/tarfile.py | 2 +- Lib/test/test_audioop.py | 15 +++ Lib/test/test_bytes.py | 19 ++++- Lib/test/test_contextlib.py | 8 ++ Lib/test/test_tarfile.py | 9 ++ Lib/test/test_tokenize.py | 20 +++++- Lib/tokenize.py | 17 ++++ Mac/BuildScript/build-installer.py | 6 +- Mac/BuildScript/openssl_sdk_makedepend.patch | 2 +- Misc/NEWS | 20 +++++ Modules/audioop.c | 38 +++++++-- Objects/bytearrayobject.c | 4 +- PCbuild/get_externals.bat | 2 +- PCbuild/pyproject.vsprops | 2 +- PCbuild/readme.txt | 2 +- configure | 5 +- configure.ac | 2 +- 26 files changed, 160 insertions(+), 31 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -248,7 +248,8 @@ help sources can be specified. Non-default user setting are saved in a .idlerc directory in the user's home directory. Problems caused by bad user configuration files are solved by editing or deleting one or more of the - files in .idlerc. + files in .idlerc. On OS X, open the configuration dialog by selecting + Preferences in the application menu. Configure Extensions Open a configuration dialog for setting preferences for extensions diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -83,7 +83,7 @@ discovery. unittest2 allows you to use these features with earlier versions of Python. - `Simple Smalltalk Testing: With Patterns `_ + `Simple Smalltalk Testing: With Patterns `_ Kent Beck's original paper on testing frameworks using the pattern shared by :mod:`unittest`. diff --git a/Doc/library/urllib.rst b/Doc/library/urllib.rst --- a/Doc/library/urllib.rst +++ b/Doc/library/urllib.rst @@ -296,7 +296,7 @@ .. note:: urllib also exposes certain utility functions like splittype, splithost and others parsing url into various components. But it is recommended to use - :mod:`urlparse` for parsing urls than using these functions directly. + :mod:`urlparse` for parsing urls rather than using these functions directly. Python 3 does not expose these helper functions from :mod:`urllib.parse` module. diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -12,9 +12,9 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "17.0" +_SETUPTOOLS_VERSION = "18.0.1" -_PIP_VERSION = "7.0.3" +_PIP_VERSION = "7.1.0" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.0.3-py2.py3-none-any.whl deleted file mode 100644 index bb0cb3138ba4ade7fa5ba3285d04f70d439f490f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.1.0-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..76fcad1c7efb6223b049967e84fda31f9fd68dfc GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-17.0-py2.py3-none-any.whl deleted file mode 100644 index a1d3561bad9c3709196b6481dd2e540b0914129b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-18.0.1-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..67aaca50a921a164fac7d721bc2aa80735c5515e GIT binary patch [stripped] diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt --- a/Lib/idlelib/help.txt +++ b/Lib/idlelib/help.txt @@ -90,10 +90,9 @@ Configure IDLE -- Open a configuration dialog. Fonts, indentation, keybindings, and color themes may be altered. Startup Preferences may be set, and Additional Help - Sources can be specified. - - On OS X this menu is not present, use - menu 'IDLE -> Preferences...' instead. + Sources can be specified. On OS X, open the + configuration dialog by selecting Preferences + in the application menu. --- Code Context -- Open a pane at the top of the edit window which shows the block context of the section of code diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -186,7 +186,7 @@ # itn() below. if s[0] != chr(0200): try: - n = int(nts(s) or "0", 8) + n = int(nts(s).strip() or "0", 8) except ValueError: raise InvalidHeaderError("invalid header") else: diff --git a/Lib/test/test_audioop.py b/Lib/test/test_audioop.py --- a/Lib/test/test_audioop.py +++ b/Lib/test/test_audioop.py @@ -210,6 +210,21 @@ self.assertEqual(audioop.lin2adpcm(b'\0' * w * 10, w, None), (b'\0' * 5, (0, 0))) + def test_invalid_adpcm_state(self): + # state must be a tuple or None, not an integer + self.assertRaises(TypeError, audioop.adpcm2lin, b'\0', 1, 555) + self.assertRaises(TypeError, audioop.lin2adpcm, b'\0', 1, 555) + # Issues #24456, #24457: index out of range + self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (0, -1)) + self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (0, 89)) + self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (0, -1)) + self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (0, 89)) + # value out of range + self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (-0x8001, 0)) + self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (0x8000, 0)) + self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (-0x8001, 0)) + self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (0x8000, 0)) + def test_lin2alaw(self): self.assertEqual(audioop.lin2alaw(datas[1], 1), b'\xd5\x87\xa4\x24\xaa\x2a\x5a') diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -722,10 +722,27 @@ for i in range(100): b += b"x" alloc = b.__alloc__() - self.assertTrue(alloc >= len(b)) + self.assertGreater(alloc, len(b)) # including trailing null byte if alloc not in seq: seq.append(alloc) + def test_init_alloc(self): + b = bytearray() + def g(): + for i in range(1, 100): + yield i + a = list(b) + self.assertEqual(a, list(range(1, len(a)+1))) + self.assertEqual(len(b), len(a)) + self.assertLessEqual(len(b), i) + alloc = b.__alloc__() + self.assertGreater(alloc, len(b)) # including trailing null byte + b.__init__(g()) + self.assertEqual(list(b), list(range(1, 100))) + self.assertEqual(len(b), 99) + alloc = b.__alloc__() + self.assertGreater(alloc, len(b)) + def test_extend(self): orig = b'hello' a = bytearray(orig) diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -106,6 +106,14 @@ baz = self._create_contextmanager_attribs() self.assertEqual(baz.__doc__, "Whee!") + def test_keywords(self): + # Ensure no keyword arguments are inhibited + @contextmanager + def woohoo(self, func, args, kwds): + yield (self, func, args, kwds) + with woohoo(self=11, func=22, args=33, kwds=44) as target: + self.assertEqual(target, (11, 22, 33, 44)) + class NestedTestCase(unittest.TestCase): # XXX This needs more work 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 @@ -1566,6 +1566,14 @@ tarinfo.tobuf(tarfile.PAX_FORMAT) +class MiscTest(unittest.TestCase): + + def test_read_number_fields(self): + # Issue 24514: Test if empty number fields are converted to zero. + self.assertEqual(tarfile.nti("\0"), 0) + self.assertEqual(tarfile.nti(" \0"), 0) + + class ContextManagerTest(unittest.TestCase): def test_basic(self): @@ -1730,6 +1738,7 @@ PaxUnicodeTest, AppendTest, LimitsTest, + MiscTest, ContextManagerTest, ] diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -559,7 +559,7 @@ from test import test_support from tokenize import (untokenize, generate_tokens, NUMBER, NAME, OP, - STRING, ENDMARKER, tok_name, Untokenizer) + STRING, ENDMARKER, tok_name, Untokenizer, tokenize) from StringIO import StringIO import os from unittest import TestCase @@ -650,12 +650,30 @@ self.assertEqual(u.untokenize(iter([token])), 'Hello ') +class TestRoundtrip(TestCase): + def roundtrip(self, code): + if isinstance(code, str): + code = code.encode('utf-8') + tokens = generate_tokens(StringIO(code).readline) + return untokenize(tokens).decode('utf-8') + + def test_indentation_semantics_retained(self): + """ + Ensure that although whitespace might be mutated in a roundtrip, + the semantic meaning of the indentation remains consistent. + """ + code = "if False:\n\tx=3\n\tx=3\n" + codelines = self.roundtrip(code).split('\n') + self.assertEqual(codelines[1], codelines[2]) + + __test__ = {"doctests" : doctests, 'decistmt': decistmt} def test_main(): from test import test_tokenize test_support.run_doctest(test_tokenize, True) test_support.run_unittest(UntokenizeTest) + test_support.run_unittest(TestRoundtrip) if __name__ == "__main__": test_main() diff --git a/Lib/tokenize.py b/Lib/tokenize.py --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -198,6 +198,8 @@ def untokenize(self, iterable): it = iter(iterable) + indents = [] + startline = False for t in it: if len(t) == 2: self.compat(t, it) @@ -205,6 +207,21 @@ tok_type, token, start, end, line = t if tok_type == ENDMARKER: break + if tok_type == INDENT: + indents.append(token) + continue + elif tok_type == DEDENT: + indents.pop() + self.prev_row, self.prev_col = end + continue + elif tok_type in (NEWLINE, NL): + startline = True + elif startline and indents: + indent = indents[-1] + if start[1] >= len(indent): + self.tokens.append(indent) + self.prev_col = len(indent) + startline = False self.add_whitespace(start) self.tokens.append(token) self.prev_row, self.prev_col = end diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2a", - url="https://www.openssl.org/source/openssl-1.0.2a.tar.gz", - checksum='a06c547dac9044161a477211049f60ef', + name="OpenSSL 1.0.2c", + url="https://www.openssl.org/source/openssl-1.0.2c.tar.gz", + checksum='8c8d81a9ae7005276e486702edbcd4b6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -2,7 +2,7 @@ # Parent 25a9af415e8c3faf591c360d5f0e361d049b2b43 # openssl_sdk_makedepend.patch # -# using openssl 1.0.2a +# using openssl 1.0.2c # # - support building with an OS X SDK # - allow "make depend" to use compilers with names other than "gcc" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #24467: Fixed possible buffer over-read in bytearray. The bytearray + object now always allocates place for trailing null byte and it's buffer now + is always null-terminated. + - Issue #19543: encode() and decode() methods and constructors of str, unicode and bytearray classes now emit deprecation warning for known non-text encodings when Python is ran with the -3 option. @@ -30,6 +34,16 @@ Library ------- +- Issue #24514: tarfile now tolerates number fields consisting of only + whitespace. + +- Issue #20387: Restore semantic round-trip correctness in tokenize/untokenize + for tab-indented blocks. + +- Issue #24456: Fixed possible buffer over-read in adpcm2lin() and lin2adpcm() + functions of the audioop module. Fixed SystemError when the state is not a + tuple. Fixed possible memory leak. + - Issue #24481: Fix possible memory corruption with large profiler info strings in hotshot. @@ -78,6 +92,12 @@ - Issue #24134: Reverted issue #24134 changes. +Build +----- + +- Issue #24432: Update Windows builds and OS X 10.5 installer to use OpenSSL + 1.0.2c. + IDLE ---- diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1420,18 +1420,29 @@ if (!audioop_check_parameters(len, size)) return NULL; - str = PyString_FromStringAndSize(NULL, len/(size*2)); - if ( str == 0 ) - return 0; - ncp = (signed char *)PyString_AsString(str); - /* Decode state, should have (value, step) */ if ( state == Py_None ) { /* First time, it seems. Set defaults */ valpred = 0; index = 0; - } else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) ) + } + else if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state must be a tuple or None"); + return NULL; + } + else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) { + return NULL; + } + else if (valpred >= 0x8000 || valpred < -0x8000 || + (size_t)index >= sizeof(stepsizeTable)/sizeof(stepsizeTable[0])) { + PyErr_SetString(PyExc_ValueError, "bad state"); + return NULL; + } + + str = PyString_FromStringAndSize(NULL, len/(size*2)); + if ( str == 0 ) return 0; + ncp = (signed char *)PyString_AsString(str); step = stepsizeTable[index]; bufferstep = 1; @@ -1529,8 +1540,19 @@ /* First time, it seems. Set defaults */ valpred = 0; index = 0; - } else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) ) - return 0; + } + else if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state must be a tuple or None"); + return NULL; + } + else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) { + return NULL; + } + else if (valpred >= 0x8000 || valpred < -0x8000 || + (size_t)index >= sizeof(stepsizeTable)/sizeof(stepsizeTable[0])) { + PyErr_SetString(PyExc_ValueError, "bad state"); + return NULL; + } if (len > (INT_MAX/2)/size) { PyErr_SetString(PyExc_MemoryError, diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -897,8 +897,10 @@ goto error; /* Append the byte */ - if (Py_SIZE(self) < self->ob_alloc) + if (Py_SIZE(self) + 1 < self->ob_alloc) { Py_SIZE(self)++; + PyByteArray_AS_STRING(self)[Py_SIZE(self)] = '\0'; + } else if (PyByteArray_Resize((PyObject *)self, Py_SIZE(self)+1) < 0) goto error; self->ob_bytes[Py_SIZE(self)-1] = value; diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -55,7 +55,7 @@ bzip2-1.0.6 db-4.7.25.0 nasm-2.11.06 - openssl-1.0.2a + openssl-1.0.2c tcl-8.5.15.0 tk-8.5.15.0 tix-8.4.3.5 diff --git a/PCbuild/pyproject.vsprops b/PCbuild/pyproject.vsprops --- a/PCbuild/pyproject.vsprops +++ b/PCbuild/pyproject.vsprops @@ -82,7 +82,7 @@ /> &5 $as_echo "$have_gcc_asm_for_x87" >&6; } if test "$have_gcc_asm_for_x87" = yes diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -3723,7 +3723,7 @@ # so we try it on all platforms. AC_MSG_CHECKING(whether we can use gcc inline assembler to get and set x87 control word) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ unsigned short cw; __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 19:03:25 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 05 Jul 2015 17:03:25 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Clean-up_call_patterns_for?= =?utf-8?q?_add/contains/discard_to_better_match_the_caller=27s?= Message-ID: <20150705170325.20885.63092@psf.io> https://hg.python.org/cpython/rev/a4be0cab2e24 changeset: 96830:a4be0cab2e24 parent: 96827:834fcda98ed9 user: Raymond Hettinger date: Sun Jul 05 10:03:20 2015 -0700 summary: Clean-up call patterns for add/contains/discard to better match the caller's needs. files: Objects/setobject.c | 73 +++++++++++++++----------------- 1 files changed, 35 insertions(+), 38 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -127,7 +127,7 @@ static int set_table_resize(PySetObject *, Py_ssize_t); static int -set_insert_key(PySetObject *so, PyObject *key, Py_hash_t hash) +set_add_key_hash(PySetObject *so, PyObject *key, Py_hash_t hash) { setentry *table = so->table; setentry *freeslot; @@ -162,7 +162,7 @@ if (cmp < 0) /* unlikely */ return -1; if (table != so->table || entry->key != startkey) /* unlikely */ - return set_insert_key(so, key, hash); + return set_add_key_hash(so, key, hash); if (cmp > 0) /* likely */ goto found_active; mask = so->mask; /* help avoid a register spill */ @@ -190,7 +190,7 @@ if (cmp < 0) return -1; if (table != so->table || entry->key != startkey) - return set_insert_key(so, key, hash); + return set_add_key_hash(so, key, hash); if (cmp > 0) goto found_active; mask = so->mask; @@ -368,7 +368,7 @@ static int set_add_entry(PySetObject *so, setentry *entry) { - return set_insert_key(so, entry->key, entry->hash); + return set_add_key_hash(so, entry->key, entry->hash); } static int @@ -382,19 +382,19 @@ if (hash == -1) return -1; } - return set_insert_key(so, key, hash); + return set_add_key_hash(so, key, hash); } #define DISCARD_NOTFOUND 0 #define DISCARD_FOUND 1 static int -set_discard_entry(PySetObject *so, setentry *oldentry) +set_discard_key_hash(PySetObject *so, PyObject *key, Py_hash_t hash) { setentry *entry; PyObject *old_key; - entry = set_lookkey(so, oldentry->key, oldentry->hash); + entry = set_lookkey(so, key, hash); if (entry == NULL) return -1; if (entry->key == NULL) @@ -408,9 +408,14 @@ } static int +set_discard_entry(PySetObject *so, setentry *entry) +{ + return set_discard_key_hash(so, entry->key, entry->hash); +} + +static int set_discard_key(PySetObject *so, PyObject *key) { - setentry entry; Py_hash_t hash; assert (PyAnySet_Check(so)); @@ -421,9 +426,7 @@ if (hash == -1) return -1; } - entry.key = key; - entry.hash = hash; - return set_discard_entry(so, &entry); + return set_discard_key_hash(so, key, hash); } static void @@ -655,7 +658,7 @@ for (i = 0; i <= other->mask; i++, other_entry++) { key = other_entry->key; if (key != NULL && key != dummy) { - if (set_insert_key(so, key, other_entry->hash)) + if (set_add_key_hash(so, key, other_entry->hash)) return -1; } } @@ -663,16 +666,20 @@ } static int +set_contains_key_hash(PySetObject *so, PyObject *key, Py_hash_t hash) +{ + setentry *lu_entry; + + lu_entry = set_lookkey(so, key, hash); + if (lu_entry != NULL) + return lu_entry->key != NULL; + return -1; +} + +static int set_contains_entry(PySetObject *so, setentry *entry) { - PyObject *key; - setentry *lu_entry; - - lu_entry = set_lookkey(so, entry->key, entry->hash); - if (lu_entry == NULL) - return -1; - key = lu_entry->key; - return key != NULL; + return set_contains_key_hash(so, entry->key, entry->hash); } static int @@ -969,7 +976,7 @@ return -1; } while (_PyDict_Next(other, &pos, &key, &value, &hash)) { - if (set_insert_key(so, key, hash)) + if (set_add_key_hash(so, key, hash)) return -1; } return 0; @@ -1291,7 +1298,6 @@ while ((key = PyIter_Next(it)) != NULL) { int rv; - setentry entry; Py_hash_t hash = PyObject_Hash(key); if (hash == -1) { @@ -1300,9 +1306,7 @@ Py_DECREF(key); return NULL; } - entry.hash = hash; - entry.key = key; - rv = set_contains_entry(so, &entry); + rv = set_contains_key_hash(so, key, hash); if (rv < 0) { Py_DECREF(it); Py_DECREF(result); @@ -1310,7 +1314,7 @@ return NULL; } if (rv) { - if (set_add_entry(result, &entry)) { + if (set_add_key_hash(result, key, hash)) { Py_DECREF(it); Py_DECREF(result); Py_DECREF(key); @@ -1444,7 +1448,6 @@ while ((key = PyIter_Next(it)) != NULL) { int rv; - setentry entry; Py_hash_t hash = PyObject_Hash(key); if (hash == -1) { @@ -1452,9 +1455,7 @@ Py_DECREF(it); return NULL; } - entry.hash = hash; - entry.key = key; - rv = set_contains_entry(so, &entry); + rv = set_contains_key_hash(so, key, hash); Py_DECREF(key); if (rv < 0) { Py_DECREF(it); @@ -1573,7 +1574,7 @@ return NULL; } if (!rv) { - if (set_insert_key((PySetObject *)result, key, hash)) { + if (set_add_key_hash((PySetObject *)result, key, hash)) { Py_DECREF(result); return NULL; } @@ -1662,19 +1663,15 @@ int rv; Py_hash_t hash; while (_PyDict_Next(other, &pos, &key, &value, &hash)) { - setentry an_entry; + Py_INCREF(key); - Py_INCREF(key); - an_entry.hash = hash; - an_entry.key = key; - - rv = set_discard_entry(so, &an_entry); + rv = set_discard_key_hash(so, key, hash); if (rv < 0) { Py_DECREF(key); return NULL; } if (rv == DISCARD_NOTFOUND) { - if (set_add_entry(so, &an_entry)) { + if (set_add_key_hash(so, key, hash)) { Py_DECREF(key); return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 19:31:36 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 05 Jul 2015 17:31:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Version_bump_f?= =?utf-8?q?or_Python_3=2E5=2E0b3_release=2E?= Message-ID: <20150705173136.87143.81896@psf.io> https://hg.python.org/cpython/rev/0035fcd9b924 changeset: 96832:0035fcd9b924 branch: 3.5 tag: v3.5.0b3 user: Larry Hastings date: Sat Jul 04 19:13:02 2015 -0700 summary: Version bump for Python 3.5.0b3 release. files: Include/patchlevel.h | 4 ++-- README | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 5 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 2 +#define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.5.0b2+" +#define PY_VERSION "3.5.0b3" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.5.0 beta 2 +This is Python version 3.5.0 beta 3 =================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 19:31:37 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 05 Jul 2015 17:31:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Added_tag_v3?= =?utf-8?q?=2E5=2E0b3_for_changeset_0035fcd9b924?= Message-ID: <20150705173136.99345.65438@psf.io> https://hg.python.org/cpython/rev/00a10c5ffd45 changeset: 96833:00a10c5ffd45 branch: 3.5 user: Larry Hastings date: Sat Jul 04 19:13:23 2015 -0700 summary: Added tag v3.5.0b3 for changeset 0035fcd9b924 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -150,3 +150,4 @@ 413e0e0004f4f954331cb8122aa55fe208984955 v3.5.0a4 071fefbb5e3db770c6c19fba9994699f121b1cea v3.5.0b1 7a088af5615bf04024e9912068f4bd8f43ed3917 v3.5.0b2 +0035fcd9b9243ae52c2e830204fd9c1f7d528534 v3.5.0b3 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 19:31:37 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 05 Jul 2015 17:31:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Post-release_f?= =?utf-8?q?ixes_for_Python_3=2E5=2E0b3=2E?= Message-ID: <20150705173137.93104.49367@psf.io> https://hg.python.org/cpython/rev/1463f1d51782 changeset: 96834:1463f1d51782 branch: 3.5 user: Larry Hastings date: Sun Jul 05 10:26:00 2015 -0700 summary: Post-release fixes for Python 3.5.0b3. files: Include/patchlevel.h | 2 +- Misc/NEWS | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.5.0b3" +#define PY_VERSION "3.5.0b3+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,18 @@ Python News +++++++++++ +What's New in Python 3.5.0 beta 4? +================================== + +Release date: 2015-07-26 + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.5.0 beta 3? ================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 19:31:37 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 05 Jul 2015 17:31:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNSk6?= =?utf-8?q?_Merge_with_ongoing_work_in_3=2E5_branch=2E?= Message-ID: <20150705173137.91470.36763@psf.io> https://hg.python.org/cpython/rev/190f25b7e799 changeset: 96835:190f25b7e799 branch: 3.5 parent: 96834:1463f1d51782 parent: 96825:4623c0edc5e6 user: Larry Hastings date: Sun Jul 05 10:31:09 2015 -0700 summary: Merge with ongoing work in 3.5 branch. files: Lib/test/test_dict.py | 14 ++++++++++++++ Lib/test/test_unpack_ex.py | 3 +++ Misc/NEWS | 4 ++++ Objects/dictobject.c | 26 +++++++++++++++++++------- Python/ceval.c | 15 +++++++++------ Tools/msi/msi.targets | 2 +- 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -937,6 +937,20 @@ d.popitem() self.check_reentrant_insertion(mutate) + def test_merge_and_mutate(self): + class X: + def __hash__(self): + return 0 + + def __eq__(self, o): + other.clear() + return False + + l = [(i,0) for i in range(1, 1337)] + other = dict(l) + other[X()] = 0 + d = {X(): 0, 1: 1} + self.assertRaises(RuntimeError, d.update, other) from test import mapping_tests diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py --- a/Lib/test/test_unpack_ex.py +++ b/Lib/test/test_unpack_ex.py @@ -128,6 +128,9 @@ ... for i in range(1000)) + "}")) 1000 + >>> {0:1, **{0:2}, 0:3, 0:4} + {0: 4} + List comprehension element unpacking >>> a, b, c = [0, 1, 2], 3, 4 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #24569: Make PEP 448 dictionary evaluation more consistent. + +- Issue #24407: Fix crash when dict is mutated while being updated. + Library ------- diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2039,20 +2039,32 @@ if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) return -1; for (i = 0, n = DK_SIZE(other->ma_keys); i < n; i++) { - PyObject *value; + PyObject *key, *value; + Py_hash_t hash; entry = &other->ma_keys->dk_entries[i]; + key = entry->me_key; + hash = entry->me_hash; if (other->ma_values) value = other->ma_values[i]; else value = entry->me_value; - if (value != NULL && - (override || - PyDict_GetItem(a, entry->me_key) == NULL)) { - if (insertdict(mp, entry->me_key, - entry->me_hash, - value) != 0) + if (value != NULL) { + int err = 0; + Py_INCREF(key); + Py_INCREF(value); + if (override || PyDict_GetItem(a, key) == NULL) + err = insertdict(mp, key, hash, value); + Py_DECREF(value); + Py_DECREF(key); + if (err != 0) return -1; + + if (n != DK_SIZE(other->ma_keys)) { + PyErr_SetString(PyExc_RuntimeError, + "dict mutated during update"); + return -1; + } } } } diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2561,22 +2561,25 @@ } TARGET(BUILD_MAP) { + int i; PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg); if (map == NULL) goto error; - while (--oparg >= 0) { + for (i = oparg; i > 0; i--) { int err; - PyObject *value = TOP(); - PyObject *key = SECOND(); - STACKADJ(-2); + PyObject *key = PEEK(2*i); + PyObject *value = PEEK(2*i - 1); err = PyDict_SetItem(map, key, value); - Py_DECREF(value); - Py_DECREF(key); if (err != 0) { Py_DECREF(map); goto error; } } + + while (oparg--) { + Py_DECREF(POP()); + Py_DECREF(POP()); + } PUSH(map); DISPATCH(); } diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets --- a/Tools/msi/msi.targets +++ b/Tools/msi/msi.targets @@ -24,7 +24,7 @@ - + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 19:31:36 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 05 Jul 2015 17:31:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Documentation_?= =?utf-8?q?fixes_for_3=2E5=2E0b3=2E?= Message-ID: <20150705173136.28944.62540@psf.io> https://hg.python.org/cpython/rev/b71dbd77a444 changeset: 96831:b71dbd77a444 branch: 3.5 parent: 96808:2dfdbbe0701b user: Larry Hastings date: Sat Jul 04 19:11:41 2015 -0700 summary: Documentation fixes for 3.5.0b3. files: Doc/tools/susp-ignored.csv | 3 ++- Lib/pydoc_data/topics.py | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -163,7 +163,6 @@ library/pyexpat,,:elem1, library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">" library/smtplib,,:port,method must support that as well as a regular host:port -library/socket,,::,"(10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0))]" library/socket,,::,'5aef:2b::8' library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" library/socket,,:len,fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) @@ -290,3 +289,5 @@ library/zipapp,82,:fn,"argument should have the form ""pkg.mod:fn"", where ""pkg.mod"" is a" library/zipapp,155,:callable,"""pkg.module:callable"" and the archive will be run by importing" library/stdtypes,3767,::,>>> m[::2].tolist() +library/sys,1115,`,# `wrapper` creates a `wrap(coro)` coroutine: +tutorial/venv,77,:c7b9645a6f35,"Python 3.4.3+ (3.4:c7b9645a6f35+, May 22 2015, 09:31:25)" diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Sat May 30 16:57:51 2015 +# Autogenerated by Sphinx on Sat Jul 4 19:11:05 2015 topics = {'assert': u'\nThe "assert" statement\n**********************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, "assert expression", is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, "assert expression1, expression2", is equivalent to\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that "__debug__" and "AssertionError" refer\nto the built-in variables with those names. In the current\nimplementation, the built-in variable "__debug__" is "True" under\nnormal circumstances, "False" when optimization is requested (command\nline option -O). The current code generator emits no code for an\nassert statement when optimization is requested at compile time. Note\nthat it is unnecessary to include the source code for the expression\nthat failed in the error message; it will be displayed as part of the\nstack trace.\n\nAssignments to "__debug__" are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', 'assignment': u'\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for\n*attributeref*, *subscription*, and *slicing*.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The\n object must be an iterable with the same number of items as there\n are targets in the target list, and the items are assigned, from\n left to right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an\n asterisk, called a "starred" target: The object must be a sequence\n with at least as many items as there are targets in the target\n list, minus one. The first items of the sequence are assigned,\n from left to right, to the targets before the starred target. The\n final items of the sequence are assigned to the targets after the\n starred target. A list of the remaining items in the sequence is\n then assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of\n items as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a "global" or "nonlocal" statement\n in the current code block: the name is bound to the object in the\n current local namespace.\n\n * Otherwise: the name is bound to the object in the global\n namespace or the outer namespace determined by "nonlocal",\n respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in\n square brackets: The object must be an iterable with the same number\n of items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, "TypeError" is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily "AttributeError").\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n "a.x" can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target "a.x" is always\n set as an instance attribute, creating it if necessary. Thus, the\n two occurrences of "a.x" do not necessarily refer to the same\n attribute: if the RHS expression refers to a class attribute, the\n LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with "property()".\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, "IndexError" is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the "__setitem__()" method is called with\n appropriate arguments.\n\n* If the target is a slicing: The primary expression in the\n reference is evaluated. It should yield a mutable sequence object\n (such as a list). The assigned object should be a sequence object\n of the same type. Next, the lower and upper bound expressions are\n evaluated, insofar they are present; defaults are zero and the\n sequence\'s length. The bounds should evaluate to integers. If\n either bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the target\n sequence allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nAlthough the definition of assignment implies that overlaps between\nthe left-hand side and the right-hand side are \'simultanenous\' (for\nexample "a, b = b, a" swaps two variables), overlaps *within* the\ncollection of assigned-to variables occur left-to-right, sometimes\nresulting in confusion. For instance, the following program prints\n"[0, 2]":\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2 # i is updated, then x[i] is updated\n print(x)\n\nSee also: **PEP 3132** - Extended Iterable Unpacking\n\n The specification for the "*target" feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions of the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nUnlike normal assignments, augmented assignments evaluate the left-\nhand side *before* evaluating the right-hand side. For example, "a[i]\n+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs\nthe addition, and lastly, it writes the result back to "a[i]".\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': u'\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a "NameError" exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier "__spam"\noccurring in a class named "Ham" will be transformed to "_Ham__spam".\nThis transformation is independent of the syntactical context in which\nthe identifier is used. If the transformed name is extremely long\n(longer than 255 characters), implementation defined truncation may\nhappen. If the class name consists only of underscores, no\ntransformation is done.\n', @@ -18,8 +18,8 @@ 'callable-types': u'\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n', 'calls': u'\nCalls\n*****\n\nA call calls a callable object (e.g., a *function*) with a possibly\nempty series of *arguments*:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nAn optional trailing comma may be present after the positional and\nkeyword arguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n"__call__()" method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal *parameter* lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a "TypeError" exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is "None", it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a "TypeError"\nexception is raised. Otherwise, the list of filled slots is used as\nthe argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use "PyArg_ParseTuple()" to parse\ntheir arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "*identifier" is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "**identifier" is present; in this case, that formal\nparameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax "*expression" appears in the function call, "expression"\nmust evaluate to an iterable. Elements from this iterable are treated\nas if they were additional positional arguments; if there are\npositional arguments *x1*, ..., *xN*, and "expression" evaluates to a\nsequence *y1*, ..., *yM*, this is equivalent to a call with M+N\npositional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the "*expression" syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the "**expression" argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the "*expression" syntax\nto be used in the same call, so in practice this confusion does not\narise.\n\nIf the syntax "**expression" appears in the function call,\n"expression" must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both "expression" and as an explicit keyword argument, a\n"TypeError" exception is raised.\n\nFormal parameters using the syntax "*identifier" or "**identifier"\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly "None", unless it raises an\nexception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a "return"\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a "__call__()" method; the effect is then the\n same as if that method was called.\n', 'class': u'\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n', - 'comparisons': u'\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. They\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', - 'compound': u'\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe "if", "while" and "for" statements implement traditional control\nflow constructs. "try" specifies exception handlers and/or cleanup\ncode for a group of statements, while the "with" statement allows the\nexecution of initialization and finalization code around a block of\ncode. Function and class definitions are also syntactically compound\nstatements.\n\nA compound statement consists of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of a suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which "if" clause a following "else" clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n"print()" calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n | async_with_stmt\n | async_for_stmt\n | async_funcdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a "NEWLINE" possibly followed by a\n"DEDENT". Also note that optional continuation clauses always begin\nwith a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling "else"\' problem is solved in Python by\nrequiring nested "if" statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe "if" statement\n==================\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n\n\nThe "while" statement\n=====================\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n\n\nThe "for" statement\n===================\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order returned by the iterator. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there is no next\nitem.\n\nThe for-loop makes assignments to the variables(s) in the target list.\nThis overwrites all previous assignments to those variables including\nthose made in the suite of the for-loop:\n\n for i in range(10):\n print(i)\n i = 5 # this will not affect the for-loop\n # because i will be overwritten with the next\n # index in the range\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, they will not have been assigned to at\nall by the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe "try" statement\n===================\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be accessed via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n >>> def f():\n ... try:\n ... 1/0\n ... finally:\n ... return 42\n ...\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe "with" statement\n====================\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n | "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n\nCoroutines\n==========\n\n\nCoroutine function definition\n-----------------------------\n\n async_funcdef ::= "async" funcdef\n\nExecution of Python coroutines can be suspended and resumed at many\npoints (see *coroutine*.) "await" expressions, "async for" and "async\nwith" can only be used in their bodies.\n\nFunctions defined with "async def" syntax are always coroutine\nfunctions, even if they do not contain "await" or "async" keywords.\n\nIt is a "SyntaxError" to use "yield" expressions in coroutines.\n\nNew in version 3.5.\n\n\nThe "async for" statement\n-------------------------\n\n async_for_stmt ::= "async" for_stmt\n\nAn *asynchronous iterable* is able to call asynchronous code in its\n*iter* implementation, and *asynchronous iterator* can call\nasynchronous code in its *next* method.\n\nThe "async for" statement allows convenient iteration over\nasynchronous iterators.\n\nThe following code:\n\n async for TARGET in ITER:\n BLOCK\n else:\n BLOCK2\n\nIs semantically equivalent to:\n\n iter = (ITER)\n iter = await type(iter).__aiter__(iter)\n running = True\n while running:\n try:\n TARGET = await type(iter).__anext__(iter)\n except StopAsyncIteration:\n running = False\n else:\n BLOCK\n else:\n BLOCK2\n\nSee also "__aiter__()" and "__anext__()" for details.\n\nNew in version 3.5.\n\n\nThe "async with" statement\n--------------------------\n\n async_with_stmt ::= "async" with_stmt\n\nAn *asynchronous context manager* is a *context manager* that is able\nto suspend execution in its *enter* and *exit* methods.\n\nThe following code:\n\n async with EXPR as VAR:\n BLOCK\n\nIs semantically equivalent to:\n\n mgr = (EXPR)\n aexit = type(mgr).__aexit__\n aenter = type(mgr).__aenter__(mgr)\n exc = True\n\n VAR = await aenter\n try:\n BLOCK\n except:\n if not await aexit(mgr, *sys.exc_info()):\n raise\n else:\n await aexit(mgr, None, None, None)\n\nSee also "__aenter__()" and "__aexit__()" for details.\n\nNew in version 3.5.\n\nSee also: **PEP 492** - Coroutines with async and await syntax\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', + 'comparisons': u'\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. They\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and "{2,3}" are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', + 'compound': u'\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe "if", "while" and "for" statements implement traditional control\nflow constructs. "try" specifies exception handlers and/or cleanup\ncode for a group of statements, while the "with" statement allows the\nexecution of initialization and finalization code around a block of\ncode. Function and class definitions are also syntactically compound\nstatements.\n\nA compound statement consists of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of a suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which "if" clause a following "else" clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n"print()" calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n | async_with_stmt\n | async_for_stmt\n | async_funcdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a "NEWLINE" possibly followed by a\n"DEDENT". Also note that optional continuation clauses always begin\nwith a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling "else"\' problem is solved in Python by\nrequiring nested "if" statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe "if" statement\n==================\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n\n\nThe "while" statement\n=====================\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n\n\nThe "for" statement\n===================\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order returned by the iterator. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there is no next\nitem.\n\nThe for-loop makes assignments to the variables(s) in the target list.\nThis overwrites all previous assignments to those variables including\nthose made in the suite of the for-loop:\n\n for i in range(10):\n print(i)\n i = 5 # this will not affect the for-loop\n # because i will be overwritten with the next\n # index in the range\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, they will not have been assigned to at\nall by the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe "try" statement\n===================\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be accessed via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n >>> def f():\n ... try:\n ... 1/0\n ... finally:\n ... return 42\n ...\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe "with" statement\n====================\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n | "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n\nCoroutines\n==========\n\nNew in version 3.5.\n\n\nCoroutine function definition\n-----------------------------\n\n async_funcdef ::= "async" funcdef\n\nExecution of Python coroutines can be suspended and resumed at many\npoints (see *coroutine*). In the body of a coroutine, any "await" and\n"async" identifiers become reserved keywords; "await" expressions,\n"async for" and "async with" can only be used in coroutine bodies.\nHowever, to simplify the parser, these keywords cannot be used on the\nsame line as a function or coroutine ("def" statement) header.\n\nFunctions defined with "async def" syntax are always coroutine\nfunctions, even if they do not contain "await" or "async" keywords.\n\nIt is a "SyntaxError" to use "yield" expressions in "async def"\ncoroutines.\n\nAn example of a coroutine function:\n\n async def func(param1, param2):\n do_stuff()\n await some_coroutine()\n\n\nThe "async for" statement\n-------------------------\n\n async_for_stmt ::= "async" for_stmt\n\nAn *asynchronous iterable* is able to call asynchronous code in its\n*iter* implementation, and *asynchronous iterator* can call\nasynchronous code in its *next* method.\n\nThe "async for" statement allows convenient iteration over\nasynchronous iterators.\n\nThe following code:\n\n async for TARGET in ITER:\n BLOCK\n else:\n BLOCK2\n\nIs semantically equivalent to:\n\n iter = (ITER)\n iter = await type(iter).__aiter__(iter)\n running = True\n while running:\n try:\n TARGET = await type(iter).__anext__(iter)\n except StopAsyncIteration:\n running = False\n else:\n BLOCK\n else:\n BLOCK2\n\nSee also "__aiter__()" and "__anext__()" for details.\n\nIt is a "SyntaxError" to use "async for" statement outside of an\n"async def" function.\n\n\nThe "async with" statement\n--------------------------\n\n async_with_stmt ::= "async" with_stmt\n\nAn *asynchronous context manager* is a *context manager* that is able\nto suspend execution in its *enter* and *exit* methods.\n\nThe following code:\n\n async with EXPR as VAR:\n BLOCK\n\nIs semantically equivalent to:\n\n mgr = (EXPR)\n aexit = type(mgr).__aexit__\n aenter = type(mgr).__aenter__(mgr)\n exc = True\n\n VAR = await aenter\n try:\n BLOCK\n except:\n if not await aexit(mgr, *sys.exc_info()):\n raise\n else:\n await aexit(mgr, None, None, None)\n\nSee also "__aenter__()" and "__aexit__()" for details.\n\nIt is a "SyntaxError" to use "async with" statement outside of an\n"async def" function.\n\nSee also: **PEP 492** - Coroutines with async and await syntax\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', 'context-managers': u'\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', 'continue': u'\nThe "continue" statement\n************************\n\n continue_stmt ::= "continue"\n\n"continue" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition or "finally"\nclause within that loop. It continues with the next cycle of the\nnearest enclosing loop.\n\nWhen "continue" passes control out of a "try" statement with a\n"finally" clause, that "finally" clause is executed before really\nstarting the next loop cycle.\n', 'conversions': u'\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works as follows:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the\n other is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string as a\nleft argument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', @@ -42,7 +42,7 @@ 'if': u'\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', 'imaginary': u'\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., "(3+4j)". Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', 'import': u'\nThe "import" statement\n**********************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nThe basic import statement (no "from" clause) is executed in two\nsteps:\n\n1. find a module, loading and initializing it if necessary\n\n2. define a name or names in the local namespace for the scope\n where the "import" statement occurs.\n\nWhen the statement contains multiple clauses (separated by commas) the\ntwo steps are carried out separately for each clause, just as though\nthe clauses had been separated out into individiual import statements.\n\nThe details of the first step, finding and loading modules are\ndescribed in greater detail in the section on the *import system*,\nwhich also describes the various types of packages and modules that\ncan be imported, as well as all the hooks that can be used to\ncustomize the import system. Note that failures in this step may\nindicate either that the module could not be located, *or* that an\nerror occurred while initializing the module, which includes execution\nof the module\'s code.\n\nIf the requested module is retrieved successfully, it will be made\navailable in the local namespace in one of three ways:\n\n* If the module name is followed by "as", then the name following\n "as" is bound directly to the imported module.\n\n* If no other name is specified, and the module being imported is a\n top level module, the module\'s name is bound in the local namespace\n as a reference to the imported module\n\n* If the module being imported is *not* a top level module, then the\n name of the top level package that contains the module is bound in\n the local namespace as a reference to the top level package. The\n imported module must be accessed using its full qualified name\n rather than directly\n\nThe "from" form uses a slightly more complex process:\n\n1. find the module specified in the "from" clause, loading and\n initializing it if necessary;\n\n2. for each of the identifiers specified in the "import" clauses:\n\n 1. check if the imported module has an attribute by that name\n\n 2. if not, attempt to import a submodule with that name and then\n check the imported module again for that attribute\n\n 3. if the attribute is not found, "ImportError" is raised.\n\n 4. otherwise, a reference to that value is stored in the local\n namespace, using the name in the "as" clause if it is present,\n otherwise using the attribute name\n\nExamples:\n\n import foo # foo imported and bound locally\n import foo.bar.baz # foo.bar.baz imported, foo bound locally\n import foo.bar.baz as fbb # foo.bar.baz imported and bound as fbb\n from foo.bar import baz # foo.bar.baz imported and bound as baz\n from foo import attr # foo imported and foo.attr bound as attr\n\nIf the list of identifiers is replaced by a star ("\'*\'"), all public\nnames defined in the module are bound in the local namespace for the\nscope where the "import" statement occurs.\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named "__all__"; if defined, it must\nbe a sequence of strings which are names defined or imported by that\nmodule. The names given in "__all__" are all considered public and\nare required to exist. If "__all__" is not defined, the set of public\nnames includes all names found in the module\'s namespace which do not\nbegin with an underscore character ("\'_\'"). "__all__" should contain\nthe entire public API. It is intended to avoid accidentally exporting\nitems that are not part of the API (such as library modules which were\nimported and used within the module).\n\nThe wild card form of import --- "from module import *" --- is only\nallowed at the module level. Attempting to use it in class or\nfunction definitions will raise a "SyntaxError".\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after "from" you\ncan specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n"from . import mod" from a module in the "pkg" package then you will\nend up importing "pkg.mod". If you execute "from ..subpkg2 import mod"\nfrom within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The\nspecification for relative imports is contained within **PEP 328**.\n\n"importlib.import_module()" is provided to support applications that\ndetermine dynamically the modules to be loaded.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python where the feature\nbecomes standard.\n\nThe future statement is intended to ease migration to future versions\nof Python that introduce incompatible changes to the language. It\nallows use of the new features on a per-module basis before the\nrelease in which the feature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are "absolute_import",\n"division", "generators", "unicode_literals", "print_function",\n"nested_scopes" and "with_statement". They are all redundant because\nthey are always enabled, and only kept for backwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module "__future__", described later, and it will\nbe imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions "exec()" and\n"compile()" that occur in a module "M" containing a future statement\nwill, by default, use the new syntax or semantics associated with the\nfuture statement. This can be controlled by optional arguments to\n"compile()" --- see the documentation of that function for details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also: **PEP 236** - Back to the __future__\n\n The original proposal for the __future__ mechanism.\n', - 'in': u'\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. They\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', + 'in': u'\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. They\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and "{2,3}" are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', 'integers': u'\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0xdeadbeef\n', 'lambda': u'\nLambdas\n*******\n\n lambda_expr ::= "lambda" [parameter_list]: expression\n lambda_expr_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda expressions (sometimes called lambda forms) are used to create\nanonymous functions. The expression "lambda arguments: expression"\nyields a function object. The unnamed object behaves like a function\nobject defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda expressions cannot contain\nstatements or annotations.\n', 'lists': u'\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | comprehension] "]"\n\nA list display yields a new list object, the contents being specified\nby either a list of expressions or a comprehension. When a comma-\nseparated list of expressions is supplied, its elements are evaluated\nfrom left to right and placed into the list object in that order.\nWhen a comprehension is supplied, the list is constructed from the\nelements resulting from the comprehension.\n', @@ -66,9 +66,9 @@ 'subscriptions': u'\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription\n(lists or dictionaries for example). User-defined objects can support\nsubscription by defining a "__getitem__()" method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a "__getitem__()"\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that "x[-1]" selects the last item of "x").\nThe resulting value must be a nonnegative integer less than the number\nof items in the sequence, and the subscription selects the item whose\nindex is that value (counting from zero). Since the support for\nnegative indices and slicing occurs in the object\'s "__getitem__()"\nmethod, subclasses overriding this method will need to explicitly add\nthat support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', 'truth': u'\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an "if" or\n"while" condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* "None"\n\n* "False"\n\n* zero of any numeric type, for example, "0", "0.0", "0j".\n\n* any empty sequence, for example, "\'\'", "()", "[]".\n\n* any empty mapping, for example, "{}".\n\n* instances of user-defined classes, if the class defines a\n "__bool__()" or "__len__()" method, when that method returns the\n integer zero or "bool" value "False". [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn "0" or "False" for false and "1" or "True" for true, unless\notherwise stated. (Important exception: the Boolean operations "or"\nand "and" always return one of their operands.)\n', 'try': u'\nThe "try" statement\n*******************\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be accessed via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n >>> def f():\n ... try:\n ... 1/0\n ... finally:\n ... return 42\n ...\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n', - 'types': u'\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name "None". It\n is used to signify the absence of a value in many situations, e.g.,\n it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n "NotImplemented". Numeric methods and rich comparison methods\n should return this value if they do not implement the operation for\n the operands provided. (The interpreter will then try the\n reflected operation, or some other fallback, depending on the\n operator.) Its truth value is true.\n\n See *Implementing the arithmetic operations* for more details.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal "..." or the\n built-in name "Ellipsis". Its truth value is true.\n\n"numbers.Number"\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n "numbers.Integral"\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers ("int")\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans ("bool")\n These represent the truth values False and True. The two\n objects representing the values "False" and "True" are the\n only Boolean objects. The Boolean type is a subtype of the\n integer type, and Boolean values behave like the values 0 and\n 1, respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ""False"" or\n ""True"" are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n "numbers.Real" ("float")\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these are\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n "numbers.Complex" ("complex")\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number "z" can be retrieved through the read-only\n attributes "z.real" and "z.imag".\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function "len()" returns the number of items\n of a sequence. When the length of a sequence is *n*, the index set\n contains the numbers 0, 1, ..., *n*-1. Item *i* of sequence *a* is\n selected by "a[i]".\n\n Sequences also support slicing: "a[i:j]" selects all items with\n index *k* such that *i* "<=" *k* "<" *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: "a[i:j:k]" selects all items of *a* with index *x* where\n "x = i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode code\n points. All the code points in the range "U+0000 - U+10FFFF"\n can be represented in a string. Python doesn\'t have a "char"\n type; instead, every code point in the string is represented\n as a string object with length "1". The built-in function\n "ord()" converts a code point from its string form to an\n integer in the range "0 - 10FFFF"; "chr()" converts an\n integer in the range "0 - 10FFFF" to the corresponding length\n "1" string object. "str.encode()" can be used to convert a\n "str" to "bytes" using the given text encoding, and\n "bytes.decode()" can be used to achieve the opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like "b\'abc\'") and the built-in function\n "bytes()" can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the "decode()"\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and "del" (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in "bytearray()" constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module "array" provides an additional example of a\n mutable sequence type, as does the "collections" module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function "len()"\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., "1" and\n "1.0"), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n "set()" constructor and can be modified afterwards by several\n methods, such as "add()".\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in "frozenset()" constructor. As a frozenset is immutable\n and *hashable*, it can be used again as an element of another\n set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation "a[k]" selects the item indexed by "k"\n from the mapping "a"; this can be used in expressions and as the\n target of assignments or "del" statements. The built-in function\n "len()" returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., "1" and "1.0")\n then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the "{...}"\n notation (see section *Dictionary displays*).\n\n The extension modules "dbm.ndbm" and "dbm.gnu" provide\n additional examples of mapping types, as does the "collections"\n module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | "__doc__" | The function\'s documentation | Writable |\n | | string, or "None" if | |\n | | unavailable; not inherited by | |\n | | subclasses | |\n +---------------------------+---------------------------------+-------------+\n | "__name__" | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__qualname__" | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | "__module__" | The name of the module the | Writable |\n | | function was defined in, or | |\n | | "None" if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | "__defaults__" | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or "None" if no arguments have | |\n | | a default value | |\n +---------------------------+---------------------------------+-------------+\n | "__code__" | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | "__globals__" | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | "__dict__" | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | "__closure__" | "None" or a tuple of cells that | Read-only |\n | | contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | "__annotations__" | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | and "\'return\'" for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | "__kwdefaults__" | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: "__self__" is the class instance\n object, "__func__" is the function object; "__doc__" is the\n method\'s documentation (same as "__func__.__doc__"); "__name__"\n is the method name (same as "__func__.__name__"); "__module__"\n is the name of the module the method was defined in, or "None"\n if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its "__self__" attribute is the instance, and the method object\n is said to be bound. The new method\'s "__func__" attribute is\n the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the "__func__"\n attribute of the new instance is not the original method object\n but its "__func__" attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its "__self__" attribute\n is the class itself, and its "__func__" attribute is the\n function object underlying the class method.\n\n When an instance method object is called, the underlying\n function ("__func__") is called, inserting the class instance\n ("__self__") in front of the argument list. For instance, when\n "C" is a class which contains a definition for a function "f()",\n and "x" is an instance of "C", calling "x.f(1)" is equivalent to\n calling "C.f(x, 1)".\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in "__self__" will actually\n be the class itself, so that calling either "x.f(1)" or "C.f(1)"\n is equivalent to calling "f(C,1)" where "f" is the underlying\n function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the "yield" statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s "iterator.__next__()" method will cause the\n function to execute until it provides a value using the "yield"\n statement. When the function executes a "return" statement or\n falls off the end, a "StopIteration" exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Coroutine functions\n A function or method which is defined using "async def" is\n called a *coroutine function*. Such a function, when called,\n returns a *coroutine* object. It may contain "await"\n expressions, as well as "async with" and "async for" statements.\n See also *Coroutines* section.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are "len()" and "math.sin()"\n ("math" is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: "__doc__" is the function\'s documentation\n string, or "None" if unavailable; "__name__" is the function\'s\n name; "__self__" is set to "None" (but see the next item);\n "__module__" is the name of the module the function was defined\n in or "None" if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n "alist.append()", assuming *alist* is a list object. In this\n case, the special read-only attribute "__self__" is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override "__new__()". The arguments of the\n call are passed to "__new__()" and, in the typical case, to\n "__init__()" to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a "__call__()" method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the "import"\n statement (see "import"), or by calling functions such as\n "importlib.import_module()" and built-in "__import__()". A module\n object has a namespace implemented by a dictionary object (this is\n the dictionary referenced by the "__globals__" attribute of\n functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., "m.x" is equivalent\n to "m.__dict__["x"]". A module object does not contain the code\n object used to initialize the module (since it isn\'t needed once\n the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., "m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n\n Special read-only attribute: "__dict__" is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: "__name__" is the module\'s name;\n "__doc__" is the module\'s documentation string, or "None" if\n unavailable; "__file__" is the pathname of the file from which the\n module was loaded, if it was loaded from a file. The "__file__"\n attribute may be missing for certain types of modules, such as C\n modules that are statically linked into the interpreter; for\n extension modules loaded dynamically from a shared library, it is\n the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., "C.x" is translated to\n "C.__dict__["x"]" (although there are a number of hooks which allow\n for other means of locating attributes). When the attribute name is\n not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n https://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class "C", say) would yield a\n class method object, it is transformed into an instance method\n object whose "__self__" attributes is "C". When it would yield a\n static method object, it is transformed into the object wrapped by\n the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its "__dict__".\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: "__name__" is the class name; "__module__" is\n the module name in which the class was defined; "__dict__" is the\n dictionary containing the class\'s namespace; "__bases__" is a tuple\n (possibly empty or a singleton) containing the base classes, in the\n order of their occurrence in the base class list; "__doc__" is the\n class\'s documentation string, or None if undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose "__self__" attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s "__dict__".\n If no class attribute is found, and the object\'s class has a\n "__getattr__()" method, that is called to satisfy the lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n "__setattr__()" or "__delattr__()" method, this is called instead\n of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: "__dict__" is the attribute dictionary;\n "__class__" is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the "open()" built-in function,\n and also "os.popen()", "os.fdopen()", and the "makefile()" method\n of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects "sys.stdin", "sys.stdout" and "sys.stderr" are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n "io.TextIOBase" abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: "co_name" gives the function name;\n "co_argcount" is the number of positional arguments (including\n arguments with default values); "co_nlocals" is the number of\n local variables used by the function (including arguments);\n "co_varnames" is a tuple containing the names of the local\n variables (starting with the argument names); "co_cellvars" is a\n tuple containing the names of local variables that are\n referenced by nested functions; "co_freevars" is a tuple\n containing the names of free variables; "co_code" is a string\n representing the sequence of bytecode instructions; "co_consts"\n is a tuple containing the literals used by the bytecode;\n "co_names" is a tuple containing the names used by the bytecode;\n "co_filename" is the filename from which the code was compiled;\n "co_firstlineno" is the first line number of the function;\n "co_lnotab" is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); "co_stacksize" is the required stack size\n (including local variables); "co_flags" is an integer encoding a\n number of flags for the interpreter.\n\n The following flag bits are defined for "co_flags": bit "0x04"\n is set if the function uses the "*arguments" syntax to accept an\n arbitrary number of positional arguments; bit "0x08" is set if\n the function uses the "**keywords" syntax to accept arbitrary\n keyword arguments; bit "0x20" is set if the function is a\n generator.\n\n Future feature declarations ("from __future__ import division")\n also use bits in "co_flags" to indicate whether a code object\n was compiled with a particular feature enabled: bit "0x2000" is\n set if the function was compiled with future division enabled;\n bits "0x10" and "0x1000" were used in earlier versions of\n Python.\n\n Other bits in "co_flags" are reserved for internal use.\n\n If a code object represents a function, the first item in\n "co_consts" is the documentation string of the function, or\n "None" if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: "f_back" is to the previous stack\n frame (towards the caller), or "None" if this is the bottom\n stack frame; "f_code" is the code object being executed in this\n frame; "f_locals" is the dictionary used to look up local\n variables; "f_globals" is used for global variables;\n "f_builtins" is used for built-in (intrinsic) names; "f_lasti"\n gives the precise instruction (this is an index into the\n bytecode string of the code object).\n\n Special writable attributes: "f_trace", if not "None", is a\n function called at the start of each source code line (this is\n used by the debugger); "f_lineno" is the current line number of\n the frame --- writing to this from within a trace function jumps\n to the given line (only for the bottom-most frame). A debugger\n can implement a Jump command (aka Set Next Statement) by writing\n to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n "RuntimeError" is raised if the frame is currently executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by "sys.exc_info()". When the program contains no\n suitable handler, the stack trace is written (nicely formatted)\n to the standard error stream; if the interpreter is interactive,\n it is also made available to the user as "sys.last_traceback".\n\n Special read-only attributes: "tb_next" is the next level in the\n stack trace (towards the frame where the exception occurred), or\n "None" if there is no next level; "tb_frame" points to the\n execution frame of the current level; "tb_lineno" gives the line\n number where the exception occurred; "tb_lasti" indicates the\n precise instruction. The line number and last instruction in\n the traceback may differ from the line number of its frame\n object if the exception occurred in a "try" statement with no\n matching except clause or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for "__getitem__()"\n methods. They are also created by the built-in "slice()"\n function.\n\n Special read-only attributes: "start" is the lower bound; "stop"\n is the upper bound; "step" is the step value; each is "None" if\n omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n "staticmethod()" constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in "classmethod()" constructor.\n', + 'types': u'\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name "None". It\n is used to signify the absence of a value in many situations, e.g.,\n it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n "NotImplemented". Numeric methods and rich comparison methods\n should return this value if they do not implement the operation for\n the operands provided. (The interpreter will then try the\n reflected operation, or some other fallback, depending on the\n operator.) Its truth value is true.\n\n See *Implementing the arithmetic operations* for more details.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal "..." or the\n built-in name "Ellipsis". Its truth value is true.\n\n"numbers.Number"\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n "numbers.Integral"\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers ("int")\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans ("bool")\n These represent the truth values False and True. The two\n objects representing the values "False" and "True" are the\n only Boolean objects. The Boolean type is a subtype of the\n integer type, and Boolean values behave like the values 0 and\n 1, respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ""False"" or\n ""True"" are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n "numbers.Real" ("float")\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these are\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n "numbers.Complex" ("complex")\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number "z" can be retrieved through the read-only\n attributes "z.real" and "z.imag".\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function "len()" returns the number of items\n of a sequence. When the length of a sequence is *n*, the index set\n contains the numbers 0, 1, ..., *n*-1. Item *i* of sequence *a* is\n selected by "a[i]".\n\n Sequences also support slicing: "a[i:j]" selects all items with\n index *k* such that *i* "<=" *k* "<" *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: "a[i:j:k]" selects all items of *a* with index *x* where\n "x = i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode code\n points. All the code points in the range "U+0000 - U+10FFFF"\n can be represented in a string. Python doesn\'t have a "char"\n type; instead, every code point in the string is represented\n as a string object with length "1". The built-in function\n "ord()" converts a code point from its string form to an\n integer in the range "0 - 10FFFF"; "chr()" converts an\n integer in the range "0 - 10FFFF" to the corresponding length\n "1" string object. "str.encode()" can be used to convert a\n "str" to "bytes" using the given text encoding, and\n "bytes.decode()" can be used to achieve the opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like "b\'abc\'") and the built-in function\n "bytes()" can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the "decode()"\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and "del" (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in "bytearray()" constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module "array" provides an additional example of a\n mutable sequence type, as does the "collections" module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function "len()"\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., "1" and\n "1.0"), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n "set()" constructor and can be modified afterwards by several\n methods, such as "add()".\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in "frozenset()" constructor. As a frozenset is immutable\n and *hashable*, it can be used again as an element of another\n set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation "a[k]" selects the item indexed by "k"\n from the mapping "a"; this can be used in expressions and as the\n target of assignments or "del" statements. The built-in function\n "len()" returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., "1" and "1.0")\n then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the "{...}"\n notation (see section *Dictionary displays*).\n\n The extension modules "dbm.ndbm" and "dbm.gnu" provide\n additional examples of mapping types, as does the "collections"\n module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | "__doc__" | The function\'s documentation | Writable |\n | | string, or "None" if | |\n | | unavailable; not inherited by | |\n | | subclasses | |\n +---------------------------+---------------------------------+-------------+\n | "__name__" | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__qualname__" | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | "__module__" | The name of the module the | Writable |\n | | function was defined in, or | |\n | | "None" if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | "__defaults__" | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or "None" if no arguments have | |\n | | a default value | |\n +---------------------------+---------------------------------+-------------+\n | "__code__" | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | "__globals__" | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | "__dict__" | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | "__closure__" | "None" or a tuple of cells that | Read-only |\n | | contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | "__annotations__" | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | and "\'return\'" for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | "__kwdefaults__" | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: "__self__" is the class instance\n object, "__func__" is the function object; "__doc__" is the\n method\'s documentation (same as "__func__.__doc__"); "__name__"\n is the method name (same as "__func__.__name__"); "__module__"\n is the name of the module the method was defined in, or "None"\n if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its "__self__" attribute is the instance, and the method object\n is said to be bound. The new method\'s "__func__" attribute is\n the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the "__func__"\n attribute of the new instance is not the original method object\n but its "__func__" attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its "__self__" attribute\n is the class itself, and its "__func__" attribute is the\n function object underlying the class method.\n\n When an instance method object is called, the underlying\n function ("__func__") is called, inserting the class instance\n ("__self__") in front of the argument list. For instance, when\n "C" is a class which contains a definition for a function "f()",\n and "x" is an instance of "C", calling "x.f(1)" is equivalent to\n calling "C.f(x, 1)".\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in "__self__" will actually\n be the class itself, so that calling either "x.f(1)" or "C.f(1)"\n is equivalent to calling "f(C,1)" where "f" is the underlying\n function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the "yield" statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s "iterator.__next__()" method will cause the\n function to execute until it provides a value using the "yield"\n statement. When the function executes a "return" statement or\n falls off the end, a "StopIteration" exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Coroutine functions\n A function or method which is defined using "async def" is\n called a *coroutine function*. Such a function, when called,\n returns a *coroutine* object. It may contain "await"\n expressions, as well as "async with" and "async for" statements.\n See also the *Coroutine Objects* section.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are "len()" and "math.sin()"\n ("math" is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: "__doc__" is the function\'s documentation\n string, or "None" if unavailable; "__name__" is the function\'s\n name; "__self__" is set to "None" (but see the next item);\n "__module__" is the name of the module the function was defined\n in or "None" if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n "alist.append()", assuming *alist* is a list object. In this\n case, the special read-only attribute "__self__" is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override "__new__()". The arguments of the\n call are passed to "__new__()" and, in the typical case, to\n "__init__()" to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a "__call__()" method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the "import"\n statement (see "import"), or by calling functions such as\n "importlib.import_module()" and built-in "__import__()". A module\n object has a namespace implemented by a dictionary object (this is\n the dictionary referenced by the "__globals__" attribute of\n functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., "m.x" is equivalent\n to "m.__dict__["x"]". A module object does not contain the code\n object used to initialize the module (since it isn\'t needed once\n the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., "m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n\n Special read-only attribute: "__dict__" is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: "__name__" is the module\'s name;\n "__doc__" is the module\'s documentation string, or "None" if\n unavailable; "__file__" is the pathname of the file from which the\n module was loaded, if it was loaded from a file. The "__file__"\n attribute may be missing for certain types of modules, such as C\n modules that are statically linked into the interpreter; for\n extension modules loaded dynamically from a shared library, it is\n the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., "C.x" is translated to\n "C.__dict__["x"]" (although there are a number of hooks which allow\n for other means of locating attributes). When the attribute name is\n not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n https://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class "C", say) would yield a\n class method object, it is transformed into an instance method\n object whose "__self__" attributes is "C". When it would yield a\n static method object, it is transformed into the object wrapped by\n the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its "__dict__".\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: "__name__" is the class name; "__module__" is\n the module name in which the class was defined; "__dict__" is the\n dictionary containing the class\'s namespace; "__bases__" is a tuple\n (possibly empty or a singleton) containing the base classes, in the\n order of their occurrence in the base class list; "__doc__" is the\n class\'s documentation string, or None if undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose "__self__" attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s "__dict__".\n If no class attribute is found, and the object\'s class has a\n "__getattr__()" method, that is called to satisfy the lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n "__setattr__()" or "__delattr__()" method, this is called instead\n of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: "__dict__" is the attribute dictionary;\n "__class__" is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the "open()" built-in function,\n and also "os.popen()", "os.fdopen()", and the "makefile()" method\n of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects "sys.stdin", "sys.stdout" and "sys.stderr" are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n "io.TextIOBase" abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: "co_name" gives the function name;\n "co_argcount" is the number of positional arguments (including\n arguments with default values); "co_nlocals" is the number of\n local variables used by the function (including arguments);\n "co_varnames" is a tuple containing the names of the local\n variables (starting with the argument names); "co_cellvars" is a\n tuple containing the names of local variables that are\n referenced by nested functions; "co_freevars" is a tuple\n containing the names of free variables; "co_code" is a string\n representing the sequence of bytecode instructions; "co_consts"\n is a tuple containing the literals used by the bytecode;\n "co_names" is a tuple containing the names used by the bytecode;\n "co_filename" is the filename from which the code was compiled;\n "co_firstlineno" is the first line number of the function;\n "co_lnotab" is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); "co_stacksize" is the required stack size\n (including local variables); "co_flags" is an integer encoding a\n number of flags for the interpreter.\n\n The following flag bits are defined for "co_flags": bit "0x04"\n is set if the function uses the "*arguments" syntax to accept an\n arbitrary number of positional arguments; bit "0x08" is set if\n the function uses the "**keywords" syntax to accept arbitrary\n keyword arguments; bit "0x20" is set if the function is a\n generator.\n\n Future feature declarations ("from __future__ import division")\n also use bits in "co_flags" to indicate whether a code object\n was compiled with a particular feature enabled: bit "0x2000" is\n set if the function was compiled with future division enabled;\n bits "0x10" and "0x1000" were used in earlier versions of\n Python.\n\n Other bits in "co_flags" are reserved for internal use.\n\n If a code object represents a function, the first item in\n "co_consts" is the documentation string of the function, or\n "None" if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: "f_back" is to the previous stack\n frame (towards the caller), or "None" if this is the bottom\n stack frame; "f_code" is the code object being executed in this\n frame; "f_locals" is the dictionary used to look up local\n variables; "f_globals" is used for global variables;\n "f_builtins" is used for built-in (intrinsic) names; "f_lasti"\n gives the precise instruction (this is an index into the\n bytecode string of the code object).\n\n Special writable attributes: "f_trace", if not "None", is a\n function called at the start of each source code line (this is\n used by the debugger); "f_lineno" is the current line number of\n the frame --- writing to this from within a trace function jumps\n to the given line (only for the bottom-most frame). A debugger\n can implement a Jump command (aka Set Next Statement) by writing\n to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n "RuntimeError" is raised if the frame is currently executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by "sys.exc_info()". When the program contains no\n suitable handler, the stack trace is written (nicely formatted)\n to the standard error stream; if the interpreter is interactive,\n it is also made available to the user as "sys.last_traceback".\n\n Special read-only attributes: "tb_next" is the next level in the\n stack trace (towards the frame where the exception occurred), or\n "None" if there is no next level; "tb_frame" points to the\n execution frame of the current level; "tb_lineno" gives the line\n number where the exception occurred; "tb_lasti" indicates the\n precise instruction. The line number and last instruction in\n the traceback may differ from the line number of its frame\n object if the exception occurred in a "try" statement with no\n matching except clause or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for "__getitem__()"\n methods. They are also created by the built-in "slice()"\n function.\n\n Special read-only attributes: "start" is the lower bound; "stop"\n is the upper bound; "step" is the step value; each is "None" if\n omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n "staticmethod()" constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in "classmethod()" constructor.\n', 'typesfunctions': u'\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: "func(argument-list)".\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', - 'typesmapping': u'\nMapping Types --- "dict"\n************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built-\nin "list", "set", and "tuple" classes, and the "collections" module.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as "1" and "1.0") then they can be used interchangeably to index\nthe same dictionary entry. (Note however, that since computers store\nfloating-point numbers as approximations it is usually unwise to use\nthem as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of "key:\nvalue" pairs within braces, for example: "{\'jack\': 4098, \'sjoerd\':\n4127}" or "{4098: \'jack\', 4127: \'sjoerd\'}", or by the "dict"\nconstructor.\n\nclass class dict(**kwarg)\nclass class dict(mapping, **kwarg)\nclass class dict(iterable, **kwarg)\n\n Return a new dictionary initialized from an optional positional\n argument and a possibly empty set of keyword arguments.\n\n If no positional argument is given, an empty dictionary is created.\n If a positional argument is given and it is a mapping object, a\n dictionary is created with the same key-value pairs as the mapping\n object. Otherwise, the positional argument must be an *iterable*\n object. Each item in the iterable must itself be an iterable with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to "{"one": 1, "two": 2, "three": 3}":\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a "KeyError" if\n *key* is not in the map.\n\n If a subclass of dict defines a method "__missing__()" and *key*\n is not present, the "d[key]" operation calls that method with\n the key *key* as argument. The "d[key]" operation then returns\n or raises whatever is returned or raised by the\n "__missing__(key)" call. No other operations or methods invoke\n "__missing__()". If "__missing__()" is not defined, "KeyError"\n is raised. "__missing__()" must be a method; it cannot be an\n instance variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n The example above shows part of the implementation of\n "collections.Counter". A different "__missing__" method is used\n by "collections.defaultdict".\n\n d[key] = value\n\n Set "d[key]" to *value*.\n\n del d[key]\n\n Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not\n in the map.\n\n key in d\n\n Return "True" if *d* has a key *key*, else "False".\n\n key not in d\n\n Equivalent to "not key in d".\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for "iter(d.keys())".\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n "fromkeys()" is a class method that returns a new dictionary.\n *value* defaults to "None".\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to "None", so\n that this method never raises a "KeyError".\n\n items()\n\n Return a new view of the dictionary\'s items ("(key, value)"\n pairs). See the *documentation of view objects*.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See the\n *documentation of view objects*.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a "KeyError" is raised.\n\n popitem()\n\n Remove and return an arbitrary "(key, value)" pair from the\n dictionary.\n\n "popitem()" is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling "popitem()" raises a "KeyError".\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to "None".\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return "None".\n\n "update()" accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: "d.update(red=1,\n blue=2)".\n\n values()\n\n Return a new view of the dictionary\'s values. See the\n *documentation of view objects*.\n\nSee also: "types.MappingProxyType" can be used to create a read-only\n view of a "dict".\n\n\nDictionary view objects\n=======================\n\nThe objects returned by "dict.keys()", "dict.values()" and\n"dict.items()" are *view objects*. They provide a dynamic view on the\ndictionary\'s entries, which means that when the dictionary changes,\nthe view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of "(key, value)") in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of "(value, key)" pairs using\n "zip()": "pairs = zip(d.values(), d.keys())". Another way to\n create the same list is "pairs = [(v, k) for (k, v) in d.items()]".\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a "RuntimeError" or fail to iterate over all entries.\n\nx in dictview\n\n Return "True" if *x* is in the underlying dictionary\'s keys, values\n or items (in the latter case, *x* should be a "(key, value)"\n tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that "(key, value)" pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class "collections.abc.Set" are available (for example, "==",\n"<", or "^").\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', + 'typesmapping': u'\nMapping Types --- "dict"\n************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built-\nin "list", "set", and "tuple" classes, and the "collections" module.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as "1" and "1.0") then they can be used interchangeably to index\nthe same dictionary entry. (Note however, that since computers store\nfloating-point numbers as approximations it is usually unwise to use\nthem as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of "key:\nvalue" pairs within braces, for example: "{\'jack\': 4098, \'sjoerd\':\n4127}" or "{4098: \'jack\', 4127: \'sjoerd\'}", or by the "dict"\nconstructor.\n\nclass class dict(**kwarg)\nclass class dict(mapping, **kwarg)\nclass class dict(iterable, **kwarg)\n\n Return a new dictionary initialized from an optional positional\n argument and a possibly empty set of keyword arguments.\n\n If no positional argument is given, an empty dictionary is created.\n If a positional argument is given and it is a mapping object, a\n dictionary is created with the same key-value pairs as the mapping\n object. Otherwise, the positional argument must be an *iterable*\n object. Each item in the iterable must itself be an iterable with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to "{"one": 1, "two": 2, "three": 3}":\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a "KeyError" if\n *key* is not in the map.\n\n If a subclass of dict defines a method "__missing__()" and *key*\n is not present, the "d[key]" operation calls that method with\n the key *key* as argument. The "d[key]" operation then returns\n or raises whatever is returned or raised by the\n "__missing__(key)" call. No other operations or methods invoke\n "__missing__()". If "__missing__()" is not defined, "KeyError"\n is raised. "__missing__()" must be a method; it cannot be an\n instance variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n The example above shows part of the implementation of\n "collections.Counter". A different "__missing__" method is used\n by "collections.defaultdict".\n\n d[key] = value\n\n Set "d[key]" to *value*.\n\n del d[key]\n\n Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not\n in the map.\n\n key in d\n\n Return "True" if *d* has a key *key*, else "False".\n\n key not in d\n\n Equivalent to "not key in d".\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for "iter(d.keys())".\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n "fromkeys()" is a class method that returns a new dictionary.\n *value* defaults to "None".\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to "None", so\n that this method never raises a "KeyError".\n\n items()\n\n Return a new view of the dictionary\'s items ("(key, value)"\n pairs). See the *documentation of view objects*.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See the\n *documentation of view objects*.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a "KeyError" is raised.\n\n popitem()\n\n Remove and return an arbitrary "(key, value)" pair from the\n dictionary.\n\n "popitem()" is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling "popitem()" raises a "KeyError".\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to "None".\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return "None".\n\n "update()" accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: "d.update(red=1,\n blue=2)".\n\n values()\n\n Return a new view of the dictionary\'s values. See the\n *documentation of view objects*.\n\n Dictionaries compare equal if and only if they have the same "(key,\n value)" pairs. Order comparisons (\'<\', \'<=\', \'>=\', \'>\') raise\n "TypeError".\n\nSee also: "types.MappingProxyType" can be used to create a read-only\n view of a "dict".\n\n\nDictionary view objects\n=======================\n\nThe objects returned by "dict.keys()", "dict.values()" and\n"dict.items()" are *view objects*. They provide a dynamic view on the\ndictionary\'s entries, which means that when the dictionary changes,\nthe view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of "(key, value)") in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of "(value, key)" pairs using\n "zip()": "pairs = zip(d.values(), d.keys())". Another way to\n create the same list is "pairs = [(v, k) for (k, v) in d.items()]".\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a "RuntimeError" or fail to iterate over all entries.\n\nx in dictview\n\n Return "True" if *x* is in the underlying dictionary\'s keys, values\n or items (in the latter case, *x* should be a "(key, value)"\n tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that "(key, value)" pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class "collections.abc.Set" are available (for example, "==",\n"<", or "^").\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', 'typesmethods': u'\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as "append()" on lists)\nand class instance methods. Built-in methods are described with the\ntypes that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the "self"\nargument to the argument list. Bound methods have two special read-\nonly attributes: "m.__self__" is the object on which the method\noperates, and "m.__func__" is the function implementing the method.\nCalling "m(arg-1, arg-2, ..., arg-n)" is completely equivalent to\ncalling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)".\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object ("meth.__func__"), setting method\nattributes on bound methods is disallowed. Attempting to set an\nattribute on a method results in an "AttributeError" being raised. In\norder to set a method attribute, you need to explicitly set it on the\nunderlying function object:\n\n >>> class C:\n ... def method(self):\n ... pass\n ...\n >>> c = C()\n >>> c.method.whoami = \'my name is method\' # can\'t set on the method\n Traceback (most recent call last):\n File "", line 1, in \n AttributeError: \'method\' object has no attribute \'whoami\'\n >>> c.method.__func__.whoami = \'my name is method\'\n >>> c.method.whoami\n \'my name is method\'\n\nSee *The standard type hierarchy* for more information.\n', 'typesmodules': u'\nModules\n*******\n\nThe only special operation on a module is attribute access: "m.name",\nwhere *m* is a module and *name* accesses a name defined in *m*\'s\nsymbol table. Module attributes can be assigned to. (Note that the\n"import" statement is not, strictly speaking, an operation on a module\nobject; "import foo" does not require a module object named *foo* to\nexist, rather it requires an (external) *definition* for a module\nnamed *foo* somewhere.)\n\nA special attribute of every module is "__dict__". This is the\ndictionary containing the module\'s symbol table. Modifying this\ndictionary will actually change the module\'s symbol table, but direct\nassignment to the "__dict__" attribute is not possible (you can write\n"m.__dict__[\'a\'] = 1", which defines "m.a" to be "1", but you can\'t\nwrite "m.__dict__ = {}"). Modifying "__dict__" directly is not\nrecommended.\n\nModules built into the interpreter are written like this: "". If loaded from a file, they are written as\n"".\n', 'typesseq': u'\nSequence Types --- "list", "tuple", "range"\n*******************************************\n\nThere are three basic sequence types: lists, tuples, and range\nobjects. Additional sequence types tailored for processing of *binary\ndata* and *text strings* are described in dedicated sections.\n\n\nCommon Sequence Operations\n==========================\n\nThe operations in the following table are supported by most sequence\ntypes, both mutable and immutable. The "collections.abc.Sequence" ABC\nis provided to make it easier to correctly implement these operations\non custom sequence types.\n\nThis table lists the sequence operations sorted in ascending priority.\nIn the table, *s* and *t* are sequences of the same type, *n*, *i*,\n*j* and *k* are integers and *x* is an arbitrary object that meets any\ntype and value restrictions imposed by *s*.\n\nThe "in" and "not in" operations have the same priorities as the\ncomparison operations. The "+" (concatenation) and "*" (repetition)\noperations have the same priority as the corresponding numeric\noperations.\n\n+----------------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+============================+==================================+============+\n| "x in s" | "True" if an item of *s* is | (1) |\n| | equal to *x*, else "False" | |\n+----------------------------+----------------------------------+------------+\n| "x not in s" | "False" if an item of *s* is | (1) |\n| | equal to *x*, else "True" | |\n+----------------------------+----------------------------------+------------+\n| "s + t" | the concatenation of *s* and *t* | (6)(7) |\n+----------------------------+----------------------------------+------------+\n| "s * n" or "n * s" | *n* shallow copies of *s* | (2)(7) |\n| | concatenated | |\n+----------------------------+----------------------------------+------------+\n| "s[i]" | *i*th item of *s*, origin 0 | (3) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j:k]" | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+----------------------------+----------------------------------+------------+\n| "len(s)" | length of *s* | |\n+----------------------------+----------------------------------+------------+\n| "min(s)" | smallest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| "max(s)" | largest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| "s.index(x[, i[, j]])" | index of the first occurrence of | (8) |\n| | *x* in *s* (at or after index | |\n| | *i* and before index *j*) | |\n+----------------------------+----------------------------------+------------+\n| "s.count(x)" | total number of occurrences of | |\n| | *x* in *s* | |\n+----------------------------+----------------------------------+------------+\n\nSequences of the same type also support comparisons. In particular,\ntuples and lists are compared lexicographically by comparing\ncorresponding elements. This means that to compare equal, every\nelement must compare equal and the two sequences must be of the same\ntype and have the same length. (For full details see *Comparisons* in\nthe language reference.)\n\nNotes:\n\n1. While the "in" and "not in" operations are used only for simple\n containment testing in the general case, some specialised sequences\n (such as "str", "bytes" and "bytearray") also use them for\n subsequence testing:\n\n >>> "gg" in "eggs"\n True\n\n2. Values of *n* less than "0" are treated as "0" (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that "[[]]" is a one-element list containing\n an empty list, so all three elements of "[[]] * 3" are (pointers\n to) this single empty list. Modifying any of the elements of\n "lists" modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of\n the string: "len(s) + i" or "len(s) + j" is substituted. But note\n that "-0" is still "0".\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that "i <= k < j". If *i* or *j* is\n greater than "len(s)", use "len(s)". If *i* is omitted or "None",\n use "0". If *j* is omitted or "None", use "len(s)". If *i* is\n greater than or equal to *j*, the slice is empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index "x = i + n*k" such that "0 <= n <\n (j-i)/k". In other words, the indices are "i", "i+k", "i+2*k",\n "i+3*k" and so on, stopping when *j* is reached (but never\n including *j*). If *i* or *j* is greater than "len(s)", use\n "len(s)". If *i* or *j* are omitted or "None", they become "end"\n values (which end depends on the sign of *k*). Note, *k* cannot be\n zero. If *k* is "None", it is treated like "1".\n\n6. Concatenating immutable sequences always results in a new\n object. This means that building up a sequence by repeated\n concatenation will have a quadratic runtime cost in the total\n sequence length. To get a linear runtime cost, you must switch to\n one of the alternatives below:\n\n * if concatenating "str" objects, you can build a list and use\n "str.join()" at the end or else write to a "io.StringIO" instance\n and retrieve its value when complete\n\n * if concatenating "bytes" objects, you can similarly use\n "bytes.join()" or "io.BytesIO", or you can do in-place\n concatenation with a "bytearray" object. "bytearray" objects are\n mutable and have an efficient overallocation mechanism\n\n * if concatenating "tuple" objects, extend a "list" instead\n\n * for other types, investigate the relevant class documentation\n\n7. Some sequence types (such as "range") only support item\n sequences that follow specific patterns, and hence don\'t support\n sequence concatenation or repetition.\n\n8. "index" raises "ValueError" when *x* is not found in *s*. When\n supported, the additional arguments to the index method allow\n efficient searching of subsections of the sequence. Passing the\n extra arguments is roughly equivalent to using "s[i:j].index(x)",\n only without copying any data and with the returned index being\n relative to the start of the sequence rather than the start of the\n slice.\n\n\nImmutable Sequence Types\n========================\n\nThe only operation that immutable sequence types generally implement\nthat is not also implemented by mutable sequence types is support for\nthe "hash()" built-in.\n\nThis support allows immutable sequences, such as "tuple" instances, to\nbe used as "dict" keys and stored in "set" and "frozenset" instances.\n\nAttempting to hash an immutable sequence that contains unhashable\nvalues will result in "TypeError".\n\n\nMutable Sequence Types\n======================\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| "s[i] = x" | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j] = t" | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j]" | same as "s[i:j] = []" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j:k]" | removes the elements of | |\n| | "s[i:j:k]" from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.append(x)" | appends *x* to the end of the | |\n| | sequence (same as | |\n| | "s[len(s):len(s)] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n| | as "del s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n| | (same as "s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.extend(t)" | extends *s* with the contents of | |\n| | *t* (same as "s[len(s):len(s)] = | |\n| | t") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.insert(i, x)" | inserts *x* into *s* at the | |\n| | index given by *i* (same as | |\n| | "s[i:i] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n| | also removes it from *s* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n| | where "s[i] == x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n\n\nLists\n=====\n\nLists are mutable sequences, typically used to store collections of\nhomogeneous items (where the precise degree of similarity will vary by\napplication).\n\nclass class list([iterable])\n\n Lists may be constructed in several ways:\n\n * Using a pair of square brackets to denote the empty list: "[]"\n\n * Using square brackets, separating items with commas: "[a]",\n "[a, b, c]"\n\n * Using a list comprehension: "[x for x in iterable]"\n\n * Using the type constructor: "list()" or "list(iterable)"\n\n The constructor builds a list whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a list, a copy is made and\n returned, similar to "iterable[:]". For example, "list(\'abc\')"\n returns "[\'a\', \'b\', \'c\']" and "list( (1, 2, 3) )" returns "[1, 2,\n 3]". If no argument is given, the constructor creates a new empty\n list, "[]".\n\n Many other operations also produce lists, including the "sorted()"\n built-in.\n\n Lists implement all of the *common* and *mutable* sequence\n operations. Lists also provide the following additional method:\n\n sort(*, key=None, reverse=None)\n\n This method sorts the list in place, using only "<" comparisons\n between items. Exceptions are not suppressed - if any comparison\n operations fail, the entire sort operation will fail (and the\n list will likely be left in a partially modified state).\n\n "sort()" accepts two arguments that can only be passed by\n keyword (*keyword-only arguments*):\n\n *key* specifies a function of one argument that is used to\n extract a comparison key from each list element (for example,\n "key=str.lower"). The key corresponding to each item in the list\n is calculated once and then used for the entire sorting process.\n The default value of "None" means that list items are sorted\n directly without calculating a separate key value.\n\n The "functools.cmp_to_key()" utility is available to convert a\n 2.x style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to "True", then the list\n elements are sorted as if each comparison were reversed.\n\n This method modifies the sequence in place for economy of space\n when sorting a large sequence. To remind users that it operates\n by side effect, it does not return the sorted sequence (use\n "sorted()" to explicitly request a new sorted list instance).\n\n The "sort()" method is guaranteed to be stable. A sort is\n stable if it guarantees not to change the relative order of\n elements that compare equal --- this is helpful for sorting in\n multiple passes (for example, sort by department, then by salary\n grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises "ValueError" if it can detect\n that the list has been mutated during a sort.\n\n\nTuples\n======\n\nTuples are immutable sequences, typically used to store collections of\nheterogeneous data (such as the 2-tuples produced by the "enumerate()"\nbuilt-in). Tuples are also used for cases where an immutable sequence\nof homogeneous data is needed (such as allowing storage in a "set" or\n"dict" instance).\n\nclass class tuple([iterable])\n\n Tuples may be constructed in a number of ways:\n\n * Using a pair of parentheses to denote the empty tuple: "()"\n\n * Using a trailing comma for a singleton tuple: "a," or "(a,)"\n\n * Separating items with commas: "a, b, c" or "(a, b, c)"\n\n * Using the "tuple()" built-in: "tuple()" or "tuple(iterable)"\n\n The constructor builds a tuple whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a tuple, it is returned\n unchanged. For example, "tuple(\'abc\')" returns "(\'a\', \'b\', \'c\')"\n and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument is\n given, the constructor creates a new empty tuple, "()".\n\n Note that it is actually the comma which makes a tuple, not the\n parentheses. The parentheses are optional, except in the empty\n tuple case, or when they are needed to avoid syntactic ambiguity.\n For example, "f(a, b, c)" is a function call with three arguments,\n while "f((a, b, c))" is a function call with a 3-tuple as the sole\n argument.\n\n Tuples implement all of the *common* sequence operations.\n\nFor heterogeneous collections of data where access by name is clearer\nthan access by index, "collections.namedtuple()" may be a more\nappropriate choice than a simple tuple object.\n\n\nRanges\n======\n\nThe "range" type represents an immutable sequence of numbers and is\ncommonly used for looping a specific number of times in "for" loops.\n\nclass class range(stop)\nclass class range(start, stop[, step])\n\n The arguments to the range constructor must be integers (either\n built-in "int" or any object that implements the "__index__"\n special method). If the *step* argument is omitted, it defaults to\n "1". If the *start* argument is omitted, it defaults to "0". If\n *step* is zero, "ValueError" is raised.\n\n For a positive *step*, the contents of a range "r" are determined\n by the formula "r[i] = start + step*i" where "i >= 0" and "r[i] <\n stop".\n\n For a negative *step*, the contents of the range are still\n determined by the formula "r[i] = start + step*i", but the\n constraints are "i >= 0" and "r[i] > stop".\n\n A range object will be empty if "r[0]" does not meet the value\n constraint. Ranges do support negative indices, but these are\n interpreted as indexing from the end of the sequence determined by\n the positive indices.\n\n Ranges containing absolute values larger than "sys.maxsize" are\n permitted but some features (such as "len()") may raise\n "OverflowError".\n\n Range examples:\n\n >>> list(range(10))\n [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n >>> list(range(1, 11))\n [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n >>> list(range(0, 30, 5))\n [0, 5, 10, 15, 20, 25]\n >>> list(range(0, 10, 3))\n [0, 3, 6, 9]\n >>> list(range(0, -10, -1))\n [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n >>> list(range(0))\n []\n >>> list(range(1, 0))\n []\n\n Ranges implement all of the *common* sequence operations except\n concatenation and repetition (due to the fact that range objects\n can only represent sequences that follow a strict pattern and\n repetition and concatenation will usually violate that pattern).\n\nThe advantage of the "range" type over a regular "list" or "tuple" is\nthat a "range" object will always take the same (small) amount of\nmemory, no matter the size of the range it represents (as it only\nstores the "start", "stop" and "step" values, calculating individual\nitems and subranges as needed).\n\nRange objects implement the "collections.abc.Sequence" ABC, and\nprovide features such as containment tests, element index lookup,\nslicing and support for negative indices (see *Sequence Types ---\nlist, tuple, range*):\n\n>>> r = range(0, 20, 2)\n>>> r\nrange(0, 20, 2)\n>>> 11 in r\nFalse\n>>> 10 in r\nTrue\n>>> r.index(10)\n5\n>>> r[5]\n10\n>>> r[:5]\nrange(0, 10, 2)\n>>> r[-1]\n18\n\nTesting range objects for equality with "==" and "!=" compares them as\nsequences. That is, two range objects are considered equal if they\nrepresent the same sequence of values. (Note that two range objects\nthat compare equal might have different "start", "stop" and "step"\nattributes, for example "range(0) == range(2, 1, 3)" or "range(0, 3,\n2) == range(0, 4, 2)".)\n\nChanged in version 3.2: Implement the Sequence ABC. Support slicing\nand negative indices. Test "int" objects for membership in constant\ntime instead of iterating through all items.\n\nChanged in version 3.3: Define \'==\' and \'!=\' to compare range objects\nbased on the sequence of values they define (instead of comparing\nbased on object identity).\n\nNew in version 3.3: The "start", "stop" and "step" attributes.\n', -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 20:18:39 2015 From: python-checkins at python.org (ned.deily) Date: Sun, 05 Jul 2015 18:18:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_merge_3=2E5=2E0b3_changes_from_3=2E5?= Message-ID: <20150705181839.4356.93433@psf.io> https://hg.python.org/cpython/rev/6905a7f8c7ac changeset: 96836:6905a7f8c7ac parent: 96830:a4be0cab2e24 parent: 96835:190f25b7e799 user: Ned Deily date: Sun Jul 05 11:17:43 2015 -0700 summary: merge 3.5.0b3 changes from 3.5 files: .hgtags | 1 + Doc/tools/susp-ignored.csv | 3 ++- Misc/NEWS | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -150,3 +150,4 @@ 413e0e0004f4f954331cb8122aa55fe208984955 v3.5.0a4 071fefbb5e3db770c6c19fba9994699f121b1cea v3.5.0b1 7a088af5615bf04024e9912068f4bd8f43ed3917 v3.5.0b2 +0035fcd9b9243ae52c2e830204fd9c1f7d528534 v3.5.0b3 diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -163,7 +163,6 @@ library/pyexpat,,:elem1, library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">" library/smtplib,,:port,method must support that as well as a regular host:port -library/socket,,::,"(10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0))]" library/socket,,::,'5aef:2b::8' library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" library/socket,,:len,fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) @@ -290,3 +289,5 @@ library/zipapp,82,:fn,"argument should have the form ""pkg.mod:fn"", where ""pkg.mod"" is a" library/zipapp,155,:callable,"""pkg.module:callable"" and the archive will be run by importing" library/stdtypes,3767,::,>>> m[::2].tolist() +library/sys,1115,`,# `wrapper` creates a `wrap(coro)` coroutine: +tutorial/venv,77,:c7b9645a6f35,"Python 3.4.3+ (3.4:c7b9645a6f35+, May 22 2015, 09:31:25)" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,13 +21,15 @@ What's New in Python 3.5.0 beta 4? ================================== -*Release date: XXXX-XX-XX* +Release date: 2015-07-26 Core and Builtins ----------------- - Issue #24569: Make PEP 448 dictionary evaluation more consistent. +- Issue #24407: Fix crash when dict is mutated while being updated. + Library ------- @@ -64,8 +66,6 @@ - Issue #19235: Add new RecursionError exception. Patch by Georg Brandl. -- Issue #24407: Fix crash when dict is mutated while being updated. - Library ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 20:46:37 2015 From: python-checkins at python.org (ned.deily) Date: Sun, 05 Jul 2015 18:46:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI0NTQw?= =?utf-8?q?=3A_fix_typo_in_json=2Edumps_docstring?= Message-ID: <20150705184636.20378.86312@psf.io> https://hg.python.org/cpython/rev/0deca75537ec changeset: 96838:0deca75537ec branch: 3.4 parent: 96815:725131a5f6cf user: Ned Deily date: Sun Jul 05 11:45:01 2015 -0700 summary: Issue #24540: fix typo in json.dumps docstring files: Lib/json/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -184,7 +184,7 @@ default=None, sort_keys=False, **kw): """Serialize ``obj`` to a JSON formatted ``str``. - If ``skipkeys`` is false then ``dict`` keys that are not basic types + If ``skipkeys`` is true then ``dict`` keys that are not basic types (``str``, ``int``, ``float``, ``bool``, ``None``) will be skipped instead of raising a ``TypeError``. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 20:46:36 2015 From: python-checkins at python.org (ned.deily) Date: Sun, 05 Jul 2015 18:46:36 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0NTQw?= =?utf-8?q?=3A_fix_typo_in_json=2Edumps_docstring?= Message-ID: <20150705184636.89409.83232@psf.io> https://hg.python.org/cpython/rev/803520a8db94 changeset: 96837:803520a8db94 branch: 2.7 parent: 96829:756876e059cb user: Ned Deily date: Sun Jul 05 11:43:59 2015 -0700 summary: Issue #24540: fix typo in json.dumps docstring files: Lib/json/__init__.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -195,10 +195,11 @@ encoding='utf-8', default=None, sort_keys=False, **kw): """Serialize ``obj`` to a JSON formatted ``str``. - If ``skipkeys`` is false then ``dict`` keys that are not basic types + If ``skipkeys`` is true then ``dict`` keys that are not basic types (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) will be skipped instead of raising a ``TypeError``. + If ``ensure_ascii`` is false, all non-ASCII characters are not escaped, and the return value may be a ``unicode`` instance. See ``dump`` for details. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 20:46:37 2015 From: python-checkins at python.org (ned.deily) Date: Sun, 05 Jul 2015 18:46:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Issue_=2324540=3A_merger_from_3=2E4?= Message-ID: <20150705184637.86787.57478@psf.io> https://hg.python.org/cpython/rev/038b4f61d9b7 changeset: 96839:038b4f61d9b7 branch: 3.5 parent: 96835:190f25b7e799 parent: 96838:0deca75537ec user: Ned Deily date: Sun Jul 05 11:45:31 2015 -0700 summary: Issue #24540: merger from 3.4 files: Lib/json/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -184,7 +184,7 @@ default=None, sort_keys=False, **kw): """Serialize ``obj`` to a JSON formatted ``str``. - If ``skipkeys`` is false then ``dict`` keys that are not basic types + If ``skipkeys`` is true then ``dict`` keys that are not basic types (``str``, ``int``, ``float``, ``bool``, ``None``) will be skipped instead of raising a ``TypeError``. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Jul 5 20:46:37 2015 From: python-checkins at python.org (ned.deily) Date: Sun, 05 Jul 2015 18:46:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2324540=3A_merger_from_3=2E5?= Message-ID: <20150705184637.48009.9677@psf.io> https://hg.python.org/cpython/rev/55755b2079fb changeset: 96840:55755b2079fb parent: 96836:6905a7f8c7ac parent: 96839:038b4f61d9b7 user: Ned Deily date: Sun Jul 05 11:46:12 2015 -0700 summary: Issue #24540: merger from 3.5 files: Lib/json/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -184,7 +184,7 @@ default=None, sort_keys=False, **kw): """Serialize ``obj`` to a JSON formatted ``str``. - If ``skipkeys`` is false then ``dict`` keys that are not basic types + If ``skipkeys`` is true then ``dict`` keys that are not basic types (``str``, ``int``, ``float``, ``bool``, ``None``) will be skipped instead of raising a ``TypeError``. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 01:06:15 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 05 Jul 2015 23:06:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Change_add/contains/discar?= =?utf-8?q?d_calls_to_pass_the_key_and_hash_instead_of_an_entry?= Message-ID: <20150705230615.26537.40002@psf.io> https://hg.python.org/cpython/rev/8701abeeb674 changeset: 96841:8701abeeb674 user: Raymond Hettinger date: Sun Jul 05 16:06:10 2015 -0700 summary: Change add/contains/discard calls to pass the key and hash instead of an entry struct. files: Objects/setobject.c | 94 ++++++++++++++------------------ 1 files changed, 42 insertions(+), 52 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -127,7 +127,7 @@ static int set_table_resize(PySetObject *, Py_ssize_t); static int -set_add_key_hash(PySetObject *so, PyObject *key, Py_hash_t hash) +set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) { setentry *table = so->table; setentry *freeslot; @@ -162,7 +162,7 @@ if (cmp < 0) /* unlikely */ return -1; if (table != so->table || entry->key != startkey) /* unlikely */ - return set_add_key_hash(so, key, hash); + return set_add_entry(so, key, hash); if (cmp > 0) /* likely */ goto found_active; mask = so->mask; /* help avoid a register spill */ @@ -190,7 +190,7 @@ if (cmp < 0) return -1; if (table != so->table || entry->key != startkey) - return set_add_key_hash(so, key, hash); + return set_add_entry(so, key, hash); if (cmp > 0) goto found_active; mask = so->mask; @@ -366,12 +366,6 @@ } static int -set_add_entry(PySetObject *so, setentry *entry) -{ - return set_add_key_hash(so, entry->key, entry->hash); -} - -static int set_add_key(PySetObject *so, PyObject *key) { Py_hash_t hash; @@ -382,14 +376,14 @@ if (hash == -1) return -1; } - return set_add_key_hash(so, key, hash); + return set_add_entry(so, key, hash); } #define DISCARD_NOTFOUND 0 #define DISCARD_FOUND 1 static int -set_discard_key_hash(PySetObject *so, PyObject *key, Py_hash_t hash) +set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash) { setentry *entry; PyObject *old_key; @@ -408,12 +402,6 @@ } static int -set_discard_entry(PySetObject *so, setentry *entry) -{ - return set_discard_key_hash(so, entry->key, entry->hash); -} - -static int set_discard_key(PySetObject *so, PyObject *key) { Py_hash_t hash; @@ -426,7 +414,7 @@ if (hash == -1) return -1; } - return set_discard_key_hash(so, key, hash); + return set_discard_entry(so, key, hash); } static void @@ -658,7 +646,7 @@ for (i = 0; i <= other->mask; i++, other_entry++) { key = other_entry->key; if (key != NULL && key != dummy) { - if (set_add_key_hash(so, key, other_entry->hash)) + if (set_add_entry(so, key, other_entry->hash)) return -1; } } @@ -666,7 +654,7 @@ } static int -set_contains_key_hash(PySetObject *so, PyObject *key, Py_hash_t hash) +set_contains_entry(PySetObject *so, PyObject *key, Py_hash_t hash) { setentry *lu_entry; @@ -677,12 +665,6 @@ } static int -set_contains_entry(PySetObject *so, setentry *entry) -{ - return set_contains_key_hash(so, entry->key, entry->hash); -} - -static int set_contains_key(PySetObject *so, PyObject *key) { setentry *entry; @@ -976,7 +958,7 @@ return -1; } while (_PyDict_Next(other, &pos, &key, &value, &hash)) { - if (set_add_key_hash(so, key, hash)) + if (set_add_entry(so, key, hash)) return -1; } return 0; @@ -1256,6 +1238,8 @@ { PySetObject *result; PyObject *key, *it, *tmp; + Py_hash_t hash; + int rv; if ((PyObject *)so == other) return set_copy(so); @@ -1275,13 +1259,15 @@ } while (set_next((PySetObject *)other, &pos, &entry)) { - int rv = set_contains_entry(so, entry); + key = entry->key; + hash = entry->hash; + rv = set_contains_entry(so, key, hash); if (rv < 0) { Py_DECREF(result); return NULL; } if (rv) { - if (set_add_entry(result, entry)) { + if (set_add_entry(result, key, hash)) { Py_DECREF(result); return NULL; } @@ -1297,16 +1283,14 @@ } while ((key = PyIter_Next(it)) != NULL) { - int rv; - Py_hash_t hash = PyObject_Hash(key); - + hash = PyObject_Hash(key); if (hash == -1) { Py_DECREF(it); Py_DECREF(result); Py_DECREF(key); return NULL; } - rv = set_contains_key_hash(so, key, hash); + rv = set_contains_entry(so, key, hash); if (rv < 0) { Py_DECREF(it); Py_DECREF(result); @@ -1314,7 +1298,7 @@ return NULL; } if (rv) { - if (set_add_key_hash(result, key, hash)) { + if (set_add_entry(result, key, hash)) { Py_DECREF(it); Py_DECREF(result); Py_DECREF(key); @@ -1415,6 +1399,7 @@ set_isdisjoint(PySetObject *so, PyObject *other) { PyObject *key, *it, *tmp; + int rv; if ((PyObject *)so == other) { if (PySet_GET_SIZE(so) == 0) @@ -1433,7 +1418,7 @@ other = tmp; } while (set_next((PySetObject *)other, &pos, &entry)) { - int rv = set_contains_entry(so, entry); + rv = set_contains_entry(so, entry->key, entry->hash); if (rv < 0) return NULL; if (rv) @@ -1447,7 +1432,6 @@ return NULL; while ((key = PyIter_Next(it)) != NULL) { - int rv; Py_hash_t hash = PyObject_Hash(key); if (hash == -1) { @@ -1455,7 +1439,7 @@ Py_DECREF(it); return NULL; } - rv = set_contains_key_hash(so, key, hash); + rv = set_contains_entry(so, key, hash); Py_DECREF(key); if (rv < 0) { Py_DECREF(it); @@ -1486,7 +1470,7 @@ Py_ssize_t pos = 0; while (set_next((PySetObject *)other, &pos, &entry)) - if (set_discard_entry(so, entry) < 0) + if (set_discard_entry(so, entry->key, entry->hash) < 0) return -1; } else { PyObject *key, *it; @@ -1546,8 +1530,11 @@ set_difference(PySetObject *so, PyObject *other) { PyObject *result; + PyObject *key; + Py_hash_t hash; setentry *entry; Py_ssize_t pos = 0; + int rv; if (!PyAnySet_Check(other) && !PyDict_CheckExact(other)) { return set_copy_and_difference(so, other); @@ -1565,16 +1552,15 @@ if (PyDict_CheckExact(other)) { while (set_next(so, &pos, &entry)) { - PyObject *key = entry->key; - Py_hash_t hash = entry->hash; - int rv; + key = entry->key; + hash = entry->hash; rv = _PyDict_Contains(other, key, hash); if (rv < 0) { Py_DECREF(result); return NULL; } if (!rv) { - if (set_add_key_hash((PySetObject *)result, key, hash)) { + if (set_add_entry((PySetObject *)result, key, hash)) { Py_DECREF(result); return NULL; } @@ -1585,13 +1571,15 @@ /* Iterate over so, checking for common elements in other. */ while (set_next(so, &pos, &entry)) { - int rv = set_contains_entry((PySetObject *)other, entry); + key = entry->key; + hash = entry->hash; + rv = set_contains_entry((PySetObject *)other, key, hash); if (rv < 0) { Py_DECREF(result); return NULL; } if (!rv) { - if (set_add_entry((PySetObject *)result, entry)) { + if (set_add_entry((PySetObject *)result, key, hash)) { Py_DECREF(result); return NULL; } @@ -1653,25 +1641,24 @@ PySetObject *otherset; PyObject *key; Py_ssize_t pos = 0; + Py_hash_t hash; setentry *entry; + int rv; if ((PyObject *)so == other) return set_clear(so); if (PyDict_CheckExact(other)) { PyObject *value; - int rv; - Py_hash_t hash; while (_PyDict_Next(other, &pos, &key, &value, &hash)) { Py_INCREF(key); - - rv = set_discard_key_hash(so, key, hash); + rv = set_discard_entry(so, key, hash); if (rv < 0) { Py_DECREF(key); return NULL; } if (rv == DISCARD_NOTFOUND) { - if (set_add_key_hash(so, key, hash)) { + if (set_add_entry(so, key, hash)) { Py_DECREF(key); return NULL; } @@ -1691,13 +1678,15 @@ } while (set_next(otherset, &pos, &entry)) { - int rv = set_discard_entry(so, entry); + key = entry->key; + hash = entry->hash; + rv = set_discard_entry(so, key, hash); if (rv < 0) { Py_DECREF(otherset); return NULL; } if (rv == DISCARD_NOTFOUND) { - if (set_add_entry(so, entry)) { + if (set_add_entry(so, key, hash)) { Py_DECREF(otherset); return NULL; } @@ -1759,6 +1748,7 @@ { setentry *entry; Py_ssize_t pos = 0; + int rv; if (!PyAnySet_Check(other)) { PyObject *tmp, *result; @@ -1773,7 +1763,7 @@ Py_RETURN_FALSE; while (set_next(so, &pos, &entry)) { - int rv = set_contains_entry((PySetObject *)other, entry); + rv = set_contains_entry((PySetObject *)other, entry->key, entry->hash); if (rv < 0) return NULL; if (!rv) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 01:27:49 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 05 Jul 2015 23:27:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Bring_related_functions_ad?= =?utf-8?q?d/contains/discard_together_in_the_code=2E?= Message-ID: <20150705232749.84918.53139@psf.io> https://hg.python.org/cpython/rev/afba0ea40e5a changeset: 96842:afba0ea40e5a user: Raymond Hettinger date: Sun Jul 05 16:27:44 2015 -0700 summary: Bring related functions add/contains/discard together in the code. files: Objects/setobject.c | 74 +++++++++++++++----------------- 1 files changed, 34 insertions(+), 40 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -366,17 +366,14 @@ } static int -set_add_key(PySetObject *so, PyObject *key) +set_contains_entry(PySetObject *so, PyObject *key, Py_hash_t hash) { - Py_hash_t hash; + setentry *entry; - if (!PyUnicode_CheckExact(key) || - (hash = ((PyASCIIObject *) key)->hash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return -1; - } - return set_add_entry(so, key, hash); + entry = set_lookkey(so, key, hash); + if (entry != NULL) + return entry->key != NULL; + return -1; } #define DISCARD_NOTFOUND 0 @@ -402,12 +399,38 @@ } static int +set_add_key(PySetObject *so, PyObject *key) +{ + Py_hash_t hash; + + if (!PyUnicode_CheckExact(key) || + (hash = ((PyASCIIObject *) key)->hash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return -1; + } + return set_add_entry(so, key, hash); +} + +static int +set_contains_key(PySetObject *so, PyObject *key) +{ + Py_hash_t hash; + + if (!PyUnicode_CheckExact(key) || + (hash = ((PyASCIIObject *) key)->hash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return -1; + } + return set_contains_entry(so, key, hash); +} + +static int set_discard_key(PySetObject *so, PyObject *key) { Py_hash_t hash; - assert (PyAnySet_Check(so)); - if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { hash = PyObject_Hash(key); @@ -653,35 +676,6 @@ return 0; } -static int -set_contains_entry(PySetObject *so, PyObject *key, Py_hash_t hash) -{ - setentry *lu_entry; - - lu_entry = set_lookkey(so, key, hash); - if (lu_entry != NULL) - return lu_entry->key != NULL; - return -1; -} - -static int -set_contains_key(PySetObject *so, PyObject *key) -{ - setentry *entry; - Py_hash_t hash; - - if (!PyUnicode_CheckExact(key) || - (hash = ((PyASCIIObject *) key)->hash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return -1; - } - entry = set_lookkey(so, key, hash); - if (entry == NULL) - return -1; - return entry->key != NULL; -} - static PyObject * set_pop(PySetObject *so) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 02:45:18 2015 From: python-checkins at python.org (nick.coghlan) Date: Mon, 06 Jul 2015 00:45:18 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_493=3A_simplify_detection?= =?utf-8?q?_of_the_capability?= Message-ID: <20150706004516.46013.46992@psf.io> https://hg.python.org/peps/rev/5f8f19025e19 changeset: 5902:5f8f19025e19 user: Nick Coghlan date: Mon Jul 06 10:45:09 2015 +1000 summary: PEP 493: simplify detection of the capability files: pep-0493.txt | 75 ++++++++++++++++++++++++++++++++------- 1 files changed, 61 insertions(+), 14 deletions(-) diff --git a/pep-0493.txt b/pep-0493.txt --- a/pep-0493.txt +++ b/pep-0493.txt @@ -72,6 +72,25 @@ Foundation or by a redistributor). +Requirements for capability detection +===================================== + +As these recommendations are intended to cover backports to earlier Python +versions, the Python version number cannot be used as a reliable means for +detecting them. Instead, the recommendations are defined to allow the presence +or absence of the feature to be determined using the following technique:: + + python -c "import ssl; ssl._relevant_attribute" + +This will fail with `AttributeError` (and hence a non-zero return code) if the +relevant capability is not available. + +The marker attributes are prefixed with an underscore to indicate the +implementation dependent nature of these capabilities - not all Python +distributions will offer them, only those that are providing a multi-stage +migration process from the legacy HTTPS handling to the new default behaviour. + + Recommendation for an environment variable based security downgrade =================================================================== @@ -91,6 +110,19 @@ including those that advertise themselves as providing Python 2.7.9 or later. +Required marker attribute +------------------------- + +The required marker attribute on the ``ssl`` module when implementing this +recommendation is:: + + _https_verify_envvar = 'PYTHONHTTPSVERIFY' + +This not only makes it straightforward to detect the presence (or absence) of +the capability, it also makes it possible to programmatically determine the +relevant environment variable name. + + Recommended modifications to the Python standard library -------------------------------------------------------- @@ -112,8 +144,10 @@ :: + _https_verify_envvar = 'PYTHONHTTPSVERIFY' + def _get_https_context_factory(): - config_setting = os.environ.get('PYTHONHTTPSVERIFY') + config_setting = os.environ.get(_https_verify_envvar) if config_setting == '0': return _create_unverified_context return create_default_context @@ -128,13 +162,10 @@ does introduce a new downgrade attack against the default security settings that potentially allows a sufficiently determined attacker to revert Python to the vulnerable configuration used in CPython 2.7.8 and earlier releases. -Such an attack requires the ability to modify the execution environment of -a Python process prior to the import of the ``ssl`` module. - -Redistributors should balance this marginal increase in risk against the -ability to offer a smoother migration path to their users when deciding whether -or not it is appropriate for them to implement this per-application "opt out" -model. +However, such an attack requires the ability to modify the execution +environment of a Python process prior to the import of the ``ssl`` module, +and any attacker with such access would already be able to modify the +behaviour of the underlying OpenSSL implementation. Recommendation for backporting to earlier Python versions @@ -161,6 +192,19 @@ certificates by default. +Required marker attribute +------------------------- + +The required marker attribute on the ``ssl`` module when implementing this +recommendation is:: + + _cert_verification_config = '' + +This not only makes it straightforward to detect the presence (or absence) of +the capability, it also makes it possible to programmatically determine the +relevant configuration file name. + + Recommended modifications to the Python standard library -------------------------------------------------------- @@ -218,9 +262,10 @@ :: + _cert_verification_config = '/etc/python/cert-verification.cfg' + def _get_https_context_factory(): # Check for a system-wide override of the default behaviour - config_file = '/etc/python/cert-verification.cfg' context_factories = { 'enable': create_default_context, 'disable': _create_unverified_context, @@ -228,7 +273,7 @@ } import ConfigParser config = ConfigParser.RawConfigParser() - config.read(config_file) + config.read(_cert_verification_config) try: verify_mode = config.get('https', 'verify') except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): @@ -268,7 +313,7 @@ (at least for the time being) Using an administrator controlled configuration file rather than an environment -variable has the essential feature of providing a smoother migraiton path, even +variable has the essential feature of providing a smoother migration path, even for applications being run with the ``-E`` switch. @@ -289,16 +334,18 @@ :: + _https_verify_envvar = 'PYTHONHTTPSVERIFY' + _cert_verification_config = '/etc/python/cert-verification.cfg' + def _get_https_context_factory(): # Check for am environmental override of the default behaviour - config_setting = os.environ.get('PYTHONHTTPSVERIFY') + config_setting = os.environ.get(_https_verify_envvar) if config_setting is not None: if config_setting == '0': return _create_unverified_context return create_default_context # Check for a system-wide override of the default behaviour - config_file = '/etc/python/cert-verification.cfg' context_factories = { 'enable': create_default_context, 'disable': _create_unverified_context, @@ -306,7 +353,7 @@ } import ConfigParser config = ConfigParser.RawConfigParser() - config.read(config_file) + config.read(_cert_verification_config) try: verify_mode = config.get('https', 'verify') except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Jul 6 05:55:14 2015 From: python-checkins at python.org (nick.coghlan) Date: Mon, 06 Jul 2015 03:55:14 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_493=3A_Add_post_date?= Message-ID: <20150706035513.86638.95247@psf.io> https://hg.python.org/peps/rev/3578d137e5e3 changeset: 5903:3578d137e5e3 user: Nick Coghlan date: Mon Jul 06 13:55:05 2015 +1000 summary: PEP 493: Add post date files: pep-0493.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/pep-0493.txt b/pep-0493.txt --- a/pep-0493.txt +++ b/pep-0493.txt @@ -7,6 +7,7 @@ Type: Informational Content-Type: text/x-rst Created: 10-May-2015 +Posted: 06-Jul-2015 Abstract -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Jul 6 06:01:03 2015 From: python-checkins at python.org (nick.coghlan) Date: Mon, 06 Jul 2015 04:01:03 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_493=3A_Credit_MAL_as_a_co?= =?utf-8?q?-author=2C_fix_headers?= Message-ID: <20150706040103.97044.20473@psf.io> https://hg.python.org/peps/rev/5a7affe76e1f changeset: 5904:5a7affe76e1f user: Nick Coghlan date: Mon Jul 06 14:00:55 2015 +1000 summary: PEP 493: Credit MAL as a co-author, fix headers files: pep-0493.txt | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pep-0493.txt b/pep-0493.txt --- a/pep-0493.txt +++ b/pep-0493.txt @@ -2,12 +2,14 @@ Title: HTTPS verification recommendations for Python 2.7 redistributors Version: $Revision$ Last-Modified: $Date$ -Author: Nick Coghlan , Robert Kuska +Author: Nick Coghlan , + Robert Kuska , + Marc-Andr? Lemburg Status: Draft Type: Informational Content-Type: text/x-rst Created: 10-May-2015 -Posted: 06-Jul-2015 +Post-History: 06-Jul-2015 Abstract -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Jul 6 07:08:26 2015 From: python-checkins at python.org (zach.ware) Date: Mon, 06 Jul 2015 05:08:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Update_Docs/to?= =?utf-8?q?ols/susp-ignored=2Ecsv?= Message-ID: <20150706050826.12463.84768@psf.io> https://hg.python.org/cpython/rev/79ed3573b977 changeset: 96843:79ed3573b977 branch: 2.7 parent: 96837:803520a8db94 user: Zachary Ware date: Mon Jul 06 00:08:15 2015 -0500 summary: Update Docs/tools/susp-ignored.csv files: Doc/tools/susp-ignored.csv | 17 +++++++++++++---- 1 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -102,7 +102,6 @@ library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">" library/smtplib,,:port,method must support that as well as a regular host:port library/socket,,::,'5aef:2b::8' -library/socket,,::,"(10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0))]" library/sqlite3,,:memory, library/sqlite3,,:who,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" library/sqlite3,,:age,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" @@ -128,6 +127,16 @@ library/urllib2,,:password,"""joe:password at python.org""" library/urllib2,,:close,Connection:close library/uuid,,:uuid,urn:uuid:12345678-1234-5678-1234-567812345678 +library/xml.etree.elementtree,,:sometag,prefix:sometag +library/xml.etree.elementtree,,:fictional,"Lancelot +library/xml.etree.elementtree,,:character,Archie Leach +library/xml.etree.elementtree,,:character,Sir Robin +library/xml.etree.elementtree,,:character,Gunther +library/xml.etree.elementtree,,:character,Commander Clement +library/xml.etree.elementtree,,:actor,"for actor in root.findall('real_person:actor', ns):" +library/xml.etree.elementtree,,:name,"name = actor.find('real_person:name', ns)" +library/xml.etree.elementtree,,:character,"for char in actor.findall('role:character', ns):" library/xmlrpclib,,:pass,http://user:pass at host:port/path library/xmlrpclib,,:pass,user:pass library/xmlrpclib,,:port,http://user:pass at host:port/path @@ -179,8 +188,8 @@ whatsnew/2.5,,:memory,:memory: whatsnew/2.5,,:step,[start:stop:step] whatsnew/2.5,,:stop,[start:stop:step] -whatsnew/2.7,735,:Sunday,'2009:4:Sunday' -whatsnew/2.7,862,::,"export PYTHONWARNINGS=all,error:::Cookie:0" -whatsnew/2.7,862,:Cookie,"export PYTHONWARNINGS=all,error:::Cookie:0" +whatsnew/2.7,,:Sunday,'2009:4:Sunday' +whatsnew/2.7,,::,"export PYTHONWARNINGS=all,error:::Cookie:0" +whatsnew/2.7,,:Cookie,"export PYTHONWARNINGS=all,error:::Cookie:0" whatsnew/2.7,,::,>>> urlparse.urlparse('http://[1080::8:800:200C:417A]/foo') whatsnew/2.7,,::,"ParseResult(scheme='http', netloc='[1080::8:800:200C:417A]'," -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 09:33:11 2015 From: python-checkins at python.org (lars.gustaebel) Date: Mon, 06 Jul 2015 07:33:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0MjU5?= =?utf-8?q?=3A_tarfile_now_raises_a_ReadError_if_an_archive_is_truncated_i?= =?utf-8?q?nside?= Message-ID: <20150706073310.30651.74344@psf.io> https://hg.python.org/cpython/rev/372aa98eb72e changeset: 96844:372aa98eb72e branch: 2.7 user: Lars Gust?bel date: Mon Jul 06 09:23:04 2015 +0200 summary: Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment. files: Lib/tarfile.py | 17 ++++++++++++++--- Lib/test/test_tarfile.py | 24 ++++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -744,12 +744,18 @@ else: return self.readsparse(size) + def __read(self, size): + buf = self.fileobj.read(size) + if len(buf) != size: + raise ReadError("unexpected end of data") + return buf + def readnormal(self, size): """Read operation for regular files. """ self.fileobj.seek(self.offset + self.position) self.position += size - return self.fileobj.read(size) + return self.__read(size) def readsparse(self, size): """Read operation for sparse files. @@ -777,7 +783,7 @@ realpos = section.realpos + self.position - section.offset self.fileobj.seek(self.offset + realpos) self.position += size - return self.fileobj.read(size) + return self.__read(size) else: self.position += size return NUL * size @@ -2336,8 +2342,13 @@ self.firstmember = None return m + # Advance the file pointer. + if self.offset != self.fileobj.tell(): + self.fileobj.seek(self.offset - 1) + if not self.fileobj.read(1): + raise ReadError("unexpected end of data") + # Read the next block. - self.fileobj.seek(self.offset) tarinfo = None while True: try: diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -285,6 +285,30 @@ "ignore_zeros=True should have skipped the %r-blocks" % char) tar.close() + def test_premature_end_of_archive(self): + for size in (512, 600, 1024, 1200): + with tarfile.open(tmpname, "w:") as tar: + t = tarfile.TarInfo("foo") + t.size = 1024 + tar.addfile(t, StringIO.StringIO("a" * 1024)) + + with open(tmpname, "r+b") as fobj: + fobj.truncate(size) + + with tarfile.open(tmpname) as tar: + with self.assertRaisesRegexp(tarfile.ReadError, "unexpected end of data"): + for t in tar: + pass + + with tarfile.open(tmpname) as tar: + t = tar.next() + + with self.assertRaisesRegexp(tarfile.ReadError, "unexpected end of data"): + tar.extract(t, TEMPDIR) + + with self.assertRaisesRegexp(tarfile.ReadError, "unexpected end of data"): + tar.extractfile(t).read() + class MiscReadTest(CommonReadTest): taropen = tarfile.TarFile.taropen diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ Library ------- +- Issue #24259: tarfile now raises a ReadError if an archive is truncated + inside a data segment. + - Issue #24514: tarfile now tolerates number fields consisting of only whitespace. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 09:33:11 2015 From: python-checkins at python.org (lars.gustaebel) Date: Mon, 06 Jul 2015 07:33:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Merge_with_3=2E4=3A_Issue_=2324259=3A_tarfile_now_raises_a_Rea?= =?utf-8?q?dError_if_an_archive_is?= Message-ID: <20150706073310.20885.50842@psf.io> https://hg.python.org/cpython/rev/59cbdc9eb3d9 changeset: 96846:59cbdc9eb3d9 branch: 3.5 parent: 96839:038b4f61d9b7 parent: 96845:c7f4f61697b7 user: Lars Gust?bel date: Mon Jul 06 09:29:41 2015 +0200 summary: Merge with 3.4: Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment. files: Lib/tarfile.py | 22 +++++++++++++++------- Lib/test/test_tarfile.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -225,7 +225,7 @@ signed_chksum = 256 + sum(struct.unpack_from("148b8x356b", buf)) return unsigned_chksum, signed_chksum -def copyfileobj(src, dst, length=None): +def copyfileobj(src, dst, length=None, exception=OSError): """Copy length bytes from fileobj src to fileobj dst. If length is None, copy the entire content. """ @@ -240,13 +240,13 @@ for b in range(blocks): buf = src.read(BUFSIZE) if len(buf) < BUFSIZE: - raise OSError("end of file reached") + raise exception("unexpected end of data") dst.write(buf) if remainder != 0: buf = src.read(remainder) if len(buf) < remainder: - raise OSError("end of file reached") + raise exception("unexpected end of data") dst.write(buf) return @@ -690,7 +690,10 @@ length = min(size, stop - self.position) if data: self.fileobj.seek(offset + (self.position - start)) - buf += self.fileobj.read(length) + b = self.fileobj.read(length) + if len(b) != length: + raise ReadError("unexpected end of data") + buf += b else: buf += NUL * length size -= length @@ -2150,9 +2153,9 @@ if tarinfo.sparse is not None: for offset, size in tarinfo.sparse: target.seek(offset) - copyfileobj(source, target, size) + copyfileobj(source, target, size, ReadError) else: - copyfileobj(source, target, tarinfo.size) + copyfileobj(source, target, tarinfo.size, ReadError) target.seek(tarinfo.size) target.truncate() @@ -2267,8 +2270,13 @@ self.firstmember = None return m + # Advance the file pointer. + if self.offset != self.fileobj.tell(): + self.fileobj.seek(self.offset - 1) + if not self.fileobj.read(1): + raise ReadError("unexpected end of data") + # Read the next block. - self.fileobj.seek(self.offset) tarinfo = None while True: try: diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -364,6 +364,29 @@ finally: tar.close() + def test_premature_end_of_archive(self): + for size in (512, 600, 1024, 1200): + with tarfile.open(tmpname, "w:") as tar: + t = tarfile.TarInfo("foo") + t.size = 1024 + tar.addfile(t, io.BytesIO(b"a" * 1024)) + + with open(tmpname, "r+b") as fobj: + fobj.truncate(size) + + with tarfile.open(tmpname) as tar: + with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): + for t in tar: + pass + + with tarfile.open(tmpname) as tar: + t = tar.next() + + with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): + tar.extract(t, TEMPDIR) + + with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): + tar.extractfile(t).read() class MiscReadTestBase(CommonReadTest): def requires_name_attribute(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,6 +17,9 @@ Library ------- +- Issue #24259: tarfile now raises a ReadError if an archive is truncated + inside a data segment. + What's New in Python 3.5.0 beta 3? ================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 09:33:11 2015 From: python-checkins at python.org (lars.gustaebel) Date: Mon, 06 Jul 2015 07:33:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E5=3A_Issue_=2324259=3A_tarfile_now_raises?= =?utf-8?q?_a_ReadError_if_an_archive_is?= Message-ID: <20150706073311.8446.90869@psf.io> https://hg.python.org/cpython/rev/6be8fa47c002 changeset: 96847:6be8fa47c002 parent: 96842:afba0ea40e5a parent: 96846:59cbdc9eb3d9 user: Lars Gust?bel date: Mon Jul 06 09:32:05 2015 +0200 summary: Merge with 3.5: Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment. files: Lib/tarfile.py | 22 +++++++++++++++------- Lib/test/test_tarfile.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -225,7 +225,7 @@ signed_chksum = 256 + sum(struct.unpack_from("148b8x356b", buf)) return unsigned_chksum, signed_chksum -def copyfileobj(src, dst, length=None): +def copyfileobj(src, dst, length=None, exception=OSError): """Copy length bytes from fileobj src to fileobj dst. If length is None, copy the entire content. """ @@ -240,13 +240,13 @@ for b in range(blocks): buf = src.read(BUFSIZE) if len(buf) < BUFSIZE: - raise OSError("end of file reached") + raise exception("unexpected end of data") dst.write(buf) if remainder != 0: buf = src.read(remainder) if len(buf) < remainder: - raise OSError("end of file reached") + raise exception("unexpected end of data") dst.write(buf) return @@ -690,7 +690,10 @@ length = min(size, stop - self.position) if data: self.fileobj.seek(offset + (self.position - start)) - buf += self.fileobj.read(length) + b = self.fileobj.read(length) + if len(b) != length: + raise ReadError("unexpected end of data") + buf += b else: buf += NUL * length size -= length @@ -2150,9 +2153,9 @@ if tarinfo.sparse is not None: for offset, size in tarinfo.sparse: target.seek(offset) - copyfileobj(source, target, size) + copyfileobj(source, target, size, ReadError) else: - copyfileobj(source, target, tarinfo.size) + copyfileobj(source, target, tarinfo.size, ReadError) target.seek(tarinfo.size) target.truncate() @@ -2267,8 +2270,13 @@ self.firstmember = None return m + # Advance the file pointer. + if self.offset != self.fileobj.tell(): + self.fileobj.seek(self.offset - 1) + if not self.fileobj.read(1): + raise ReadError("unexpected end of data") + # Read the next block. - self.fileobj.seek(self.offset) tarinfo = None while True: try: diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -364,6 +364,29 @@ finally: tar.close() + def test_premature_end_of_archive(self): + for size in (512, 600, 1024, 1200): + with tarfile.open(tmpname, "w:") as tar: + t = tarfile.TarInfo("foo") + t.size = 1024 + tar.addfile(t, io.BytesIO(b"a" * 1024)) + + with open(tmpname, "r+b") as fobj: + fobj.truncate(size) + + with tarfile.open(tmpname) as tar: + with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): + for t in tar: + pass + + with tarfile.open(tmpname) as tar: + t = tar.next() + + with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): + tar.extract(t, TEMPDIR) + + with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): + tar.extractfile(t).read() class MiscReadTestBase(CommonReadTest): def requires_name_attribute(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -33,6 +33,9 @@ Library ------- +- Issue #24259: tarfile now raises a ReadError if an archive is truncated + inside a data segment. + What's New in Python 3.5.0 beta 3? ================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 09:33:11 2015 From: python-checkins at python.org (lars.gustaebel) Date: Mon, 06 Jul 2015 07:33:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI0MjU5?= =?utf-8?q?=3A_tarfile_now_raises_a_ReadError_if_an_archive_is_truncated_i?= =?utf-8?q?nside?= Message-ID: <20150706073310.31722.38618@psf.io> https://hg.python.org/cpython/rev/c7f4f61697b7 changeset: 96845:c7f4f61697b7 branch: 3.4 parent: 96838:0deca75537ec user: Lars Gust?bel date: Mon Jul 06 09:27:24 2015 +0200 summary: Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment. files: Lib/tarfile.py | 22 +++++++++++++++------- Lib/test/test_tarfile.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -225,7 +225,7 @@ signed_chksum = 256 + sum(struct.unpack_from("148b8x356b", buf)) return unsigned_chksum, signed_chksum -def copyfileobj(src, dst, length=None): +def copyfileobj(src, dst, length=None, exception=OSError): """Copy length bytes from fileobj src to fileobj dst. If length is None, copy the entire content. """ @@ -240,13 +240,13 @@ for b in range(blocks): buf = src.read(BUFSIZE) if len(buf) < BUFSIZE: - raise OSError("end of file reached") + raise exception("unexpected end of data") dst.write(buf) if remainder != 0: buf = src.read(remainder) if len(buf) < remainder: - raise OSError("end of file reached") + raise exception("unexpected end of data") dst.write(buf) return @@ -690,7 +690,10 @@ length = min(size, stop - self.position) if data: self.fileobj.seek(offset + (self.position - start)) - buf += self.fileobj.read(length) + b = self.fileobj.read(length) + if len(b) != length: + raise ReadError("unexpected end of data") + buf += b else: buf += NUL * length size -= length @@ -2132,9 +2135,9 @@ if tarinfo.sparse is not None: for offset, size in tarinfo.sparse: target.seek(offset) - copyfileobj(source, target, size) + copyfileobj(source, target, size, ReadError) else: - copyfileobj(source, target, tarinfo.size) + copyfileobj(source, target, tarinfo.size, ReadError) target.seek(tarinfo.size) target.truncate() @@ -2244,8 +2247,13 @@ self.firstmember = None return m + # Advance the file pointer. + if self.offset != self.fileobj.tell(): + self.fileobj.seek(self.offset - 1) + if not self.fileobj.read(1): + raise ReadError("unexpected end of data") + # Read the next block. - self.fileobj.seek(self.offset) tarinfo = None while True: try: diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -349,6 +349,29 @@ finally: tar.close() + def test_premature_end_of_archive(self): + for size in (512, 600, 1024, 1200): + with tarfile.open(tmpname, "w:") as tar: + t = tarfile.TarInfo("foo") + t.size = 1024 + tar.addfile(t, io.BytesIO(b"a" * 1024)) + + with open(tmpname, "r+b") as fobj: + fobj.truncate(size) + + with tarfile.open(tmpname) as tar: + with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): + for t in tar: + pass + + with tarfile.open(tmpname) as tar: + t = tar.next() + + with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): + tar.extract(t, TEMPDIR) + + with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): + tar.extractfile(t).read() class MiscReadTestBase(CommonReadTest): def requires_name_attribute(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,9 @@ Library ------- +- Issue #24259: tarfile now raises a ReadError if an archive is truncated + inside a data segment. + - Issue #24552: Fix use after free in an error case of the _pickle module. - Issue #24514: tarfile now tolerates number fields consisting of only -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Mon Jul 6 10:43:51 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 06 Jul 2015 08:43:51 +0000 Subject: [Python-checkins] Daily reference leaks (afba0ea40e5a): sum=7 Message-ID: <20150706084351.86369.70785@psf.io> results for afba0ea40e5a on branch "default" -------------------------------------------- test_asyncio leaked [0, 3, 0] memory blocks, sum=3 test_functools leaked [0, 2, 2] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/refloghcizvG', '--timeout', '7200'] From python-checkins at python.org Mon Jul 6 13:23:56 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 06 Jul 2015 11:23:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE4Njg0?= =?utf-8?q?=3A_Fixed_reading_out_of_the_buffer_in_the_re_module=2E?= Message-ID: <20150706112356.2656.76244@psf.io> https://hg.python.org/cpython/rev/389795b7c703 changeset: 96849:389795b7c703 branch: 3.4 parent: 96845:c7f4f61697b7 user: Serhiy Storchaka date: Mon Jul 06 13:58:33 2015 +0300 summary: Issue #18684: Fixed reading out of the buffer in the re module. files: Misc/NEWS | 2 ++ Modules/_sre.c | 26 +++++++++++++++++++++----- Modules/sre_lib.h | 29 ++++++++++++++++++++--------- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,8 @@ Library ------- +- Issue #18684: Fixed reading out of the buffer in the re module. + - Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment. diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -883,7 +883,7 @@ } if (state.start == state.ptr) { - if (last == state.end) + if (last == state.end || state.ptr == state.end) break; /* skip one character */ state.start = (void*) ((char*) state.ptr + state.charsize); @@ -1081,6 +1081,8 @@ next: /* move on */ + if (state.ptr == state.end) + break; if (state.ptr == state.start) state.start = (void*) ((char*) state.ptr + state.charsize); else @@ -2567,6 +2569,9 @@ PyObject* match; Py_ssize_t status; + if (state->start == NULL) + Py_RETURN_NONE; + state_reset(state); state->ptr = state->start; @@ -2578,10 +2583,14 @@ match = pattern_new_match((PatternObject*) self->pattern, state, status); - if (status == 0 || state->ptr == state->start) + if (status == 0) + state->start = NULL; + else if (state->ptr != state->start) + state->start = state->ptr; + else if (state->ptr != state->end) state->start = (void*) ((char*) state->ptr + state->charsize); else - state->start = state->ptr; + state->start = NULL; return match; } @@ -2594,6 +2603,9 @@ PyObject* match; Py_ssize_t status; + if (state->start == NULL) + Py_RETURN_NONE; + state_reset(state); state->ptr = state->start; @@ -2605,10 +2617,14 @@ match = pattern_new_match((PatternObject*) self->pattern, state, status); - if (status == 0 || state->ptr == state->start) + if (status == 0) + state->start = NULL; + else if (state->ptr != state->start) + state->start = state->ptr; + else if (state->ptr != state->end) state->start = (void*) ((char*) state->ptr + state->charsize); else - state->start = state->ptr; + state->start = NULL; return match; } diff --git a/Modules/sre_lib.h b/Modules/sre_lib.h --- a/Modules/sre_lib.h +++ b/Modules/sre_lib.h @@ -30,7 +30,7 @@ SRE_IS_LINEBREAK((int) ptr[-1])); case SRE_AT_END: - return (((void*) (ptr+1) == state->end && + return (((SRE_CHAR *)state->end - ptr == 1 && SRE_IS_LINEBREAK((int) ptr[0])) || ((void*) ptr == state->end)); @@ -1093,9 +1093,9 @@ /* */ TRACE(("|%p|%p|ASSERT %d\n", ctx->pattern, ctx->ptr, ctx->pattern[1])); + if (ctx->ptr - (SRE_CHAR *)state->beginning < (Py_ssize_t)ctx->pattern[1]) + RETURN_FAILURE; state->ptr = ctx->ptr - ctx->pattern[1]; - if (state->ptr < state->beginning) - RETURN_FAILURE; DO_JUMP0(JUMP_ASSERT, jump_assert, ctx->pattern+2); RETURN_ON_FAILURE(ret); ctx->pattern += ctx->pattern[0]; @@ -1106,8 +1106,8 @@ /* */ TRACE(("|%p|%p|ASSERT_NOT %d\n", ctx->pattern, ctx->ptr, ctx->pattern[1])); - state->ptr = ctx->ptr - ctx->pattern[1]; - if (state->ptr >= state->beginning) { + if (ctx->ptr - (SRE_CHAR *)state->beginning >= (Py_ssize_t)ctx->pattern[1]) { + state->ptr = ctx->ptr - ctx->pattern[1]; DO_JUMP0(JUMP_ASSERT_NOT, jump_assert_not, ctx->pattern+2); if (ret) { RETURN_ON_ERROR(ret); @@ -1199,12 +1199,20 @@ SRE_CODE* overlap = NULL; int flags = 0; + if (ptr > end) + return 0; + if (pattern[0] == SRE_OP_INFO) { /* optimization info block */ /* <1=skip> <2=flags> <3=min> <4=max> <5=prefix info> */ flags = pattern[2]; + if (pattern[3] && end - ptr < (Py_ssize_t)pattern[3]) { + TRACE(("reject (got %u chars, need %u)\n", + (unsigned int)(end - ptr), pattern[3])); + return 0; + } if (pattern[3] > 1) { /* adjust end point (but make sure we leave at least one character in there, so literal search will work) */ @@ -1322,15 +1330,18 @@ break; ptr++; } - } else + } else { /* general case */ - while (ptr <= end) { + assert(ptr <= end); + while (1) { TRACE(("|%p|%p|SEARCH\n", pattern, ptr)); - state->start = state->ptr = ptr++; + state->start = state->ptr = ptr; status = SRE(match)(state, pattern, 0); - if (status != 0) + if (status != 0 || ptr >= end) break; + ptr++; } + } return status; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 13:23:56 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 06 Jul 2015 11:23:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Issue_=2318684=3A_Fixed_reading_out_of_the_buffer_in_the_re_mo?= =?utf-8?q?dule=2E?= Message-ID: <20150706112356.3300.40740@psf.io> https://hg.python.org/cpython/rev/5adf995d443f changeset: 96850:5adf995d443f branch: 3.5 parent: 96846:59cbdc9eb3d9 parent: 96849:389795b7c703 user: Serhiy Storchaka date: Mon Jul 06 14:03:01 2015 +0300 summary: Issue #18684: Fixed reading out of the buffer in the re module. files: Misc/NEWS | 2 ++ Modules/_sre.c | 26 +++++++++++++++++++++----- Modules/sre_lib.h | 29 ++++++++++++++++++++--------- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,6 +17,8 @@ Library ------- +- Issue #18684: Fixed reading out of the buffer in the re module. + - Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment. diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -994,7 +994,7 @@ } if (state.start == state.ptr) { - if (last == state.end) + if (last == state.end || state.ptr == state.end) break; /* skip one character */ state.start = (void*) ((char*) state.ptr + state.charsize); @@ -1191,6 +1191,8 @@ next: /* move on */ + if (state.ptr == state.end) + break; if (state.ptr == state.start) state.start = (void*) ((char*) state.ptr + state.charsize); else @@ -2564,6 +2566,9 @@ PyObject* match; Py_ssize_t status; + if (state->start == NULL) + Py_RETURN_NONE; + state_reset(state); state->ptr = state->start; @@ -2575,10 +2580,14 @@ match = pattern_new_match((PatternObject*) self->pattern, state, status); - if (status == 0 || state->ptr == state->start) + if (status == 0) + state->start = NULL; + else if (state->ptr != state->start) + state->start = state->ptr; + else if (state->ptr != state->end) state->start = (void*) ((char*) state->ptr + state->charsize); else - state->start = state->ptr; + state->start = NULL; return match; } @@ -2597,6 +2606,9 @@ PyObject* match; Py_ssize_t status; + if (state->start == NULL) + Py_RETURN_NONE; + state_reset(state); state->ptr = state->start; @@ -2608,10 +2620,14 @@ match = pattern_new_match((PatternObject*) self->pattern, state, status); - if (status == 0 || state->ptr == state->start) + if (status == 0) + state->start = NULL; + else if (state->ptr != state->start) + state->start = state->ptr; + else if (state->ptr != state->end) state->start = (void*) ((char*) state->ptr + state->charsize); else - state->start = state->ptr; + state->start = NULL; return match; } diff --git a/Modules/sre_lib.h b/Modules/sre_lib.h --- a/Modules/sre_lib.h +++ b/Modules/sre_lib.h @@ -30,7 +30,7 @@ SRE_IS_LINEBREAK((int) ptr[-1])); case SRE_AT_END: - return (((void*) (ptr+1) == state->end && + return (((SRE_CHAR *)state->end - ptr == 1 && SRE_IS_LINEBREAK((int) ptr[0])) || ((void*) ptr == state->end)); @@ -1109,9 +1109,9 @@ /* */ TRACE(("|%p|%p|ASSERT %d\n", ctx->pattern, ctx->ptr, ctx->pattern[1])); + if (ctx->ptr - (SRE_CHAR *)state->beginning < (Py_ssize_t)ctx->pattern[1]) + RETURN_FAILURE; state->ptr = ctx->ptr - ctx->pattern[1]; - if (state->ptr < state->beginning) - RETURN_FAILURE; DO_JUMP0(JUMP_ASSERT, jump_assert, ctx->pattern+2); RETURN_ON_FAILURE(ret); ctx->pattern += ctx->pattern[0]; @@ -1122,8 +1122,8 @@ /* */ TRACE(("|%p|%p|ASSERT_NOT %d\n", ctx->pattern, ctx->ptr, ctx->pattern[1])); - state->ptr = ctx->ptr - ctx->pattern[1]; - if (state->ptr >= state->beginning) { + if (ctx->ptr - (SRE_CHAR *)state->beginning >= (Py_ssize_t)ctx->pattern[1]) { + state->ptr = ctx->ptr - ctx->pattern[1]; DO_JUMP0(JUMP_ASSERT_NOT, jump_assert_not, ctx->pattern+2); if (ret) { RETURN_ON_ERROR(ret); @@ -1215,12 +1215,20 @@ SRE_CODE* overlap = NULL; int flags = 0; + if (ptr > end) + return 0; + if (pattern[0] == SRE_OP_INFO) { /* optimization info block */ /* <1=skip> <2=flags> <3=min> <4=max> <5=prefix info> */ flags = pattern[2]; + if (pattern[3] && end - ptr < (Py_ssize_t)pattern[3]) { + TRACE(("reject (got %u chars, need %u)\n", + (unsigned int)(end - ptr), pattern[3])); + return 0; + } if (pattern[3] > 1) { /* adjust end point (but make sure we leave at least one character in there, so literal search will work) */ @@ -1338,15 +1346,18 @@ break; ptr++; } - } else + } else { /* general case */ - while (ptr <= end) { + assert(ptr <= end); + while (1) { TRACE(("|%p|%p|SEARCH\n", pattern, ptr)); - state->start = state->ptr = ptr++; + state->start = state->ptr = ptr; status = SRE(match)(state, pattern, 0); - if (status != 0) + if (status != 0 || ptr >= end) break; + ptr++; } + } return status; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 13:23:56 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 06 Jul 2015 11:23:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318684=3A_Fixed_reading_out_of_the_buffer_in_the?= =?utf-8?q?_re_module=2E?= Message-ID: <20150706112356.8271.70592@psf.io> https://hg.python.org/cpython/rev/bb9fc884a838 changeset: 96851:bb9fc884a838 parent: 96847:6be8fa47c002 parent: 96850:5adf995d443f user: Serhiy Storchaka date: Mon Jul 06 14:23:04 2015 +0300 summary: Issue #18684: Fixed reading out of the buffer in the re module. files: Misc/NEWS | 2 ++ Modules/_sre.c | 26 +++++++++++++++++++++----- Modules/sre_lib.h | 29 ++++++++++++++++++++--------- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -33,6 +33,8 @@ Library ------- +- Issue #18684: Fixed reading out of the buffer in the re module. + - Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment. diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -991,7 +991,7 @@ } if (state.start == state.ptr) { - if (last == state.end) + if (last == state.end || state.ptr == state.end) break; /* skip one character */ state.start = (void*) ((char*) state.ptr + state.charsize); @@ -1188,6 +1188,8 @@ next: /* move on */ + if (state.ptr == state.end) + break; if (state.ptr == state.start) state.start = (void*) ((char*) state.ptr + state.charsize); else @@ -2561,6 +2563,9 @@ PyObject* match; Py_ssize_t status; + if (state->start == NULL) + Py_RETURN_NONE; + state_reset(state); state->ptr = state->start; @@ -2572,10 +2577,14 @@ match = pattern_new_match((PatternObject*) self->pattern, state, status); - if (status == 0 || state->ptr == state->start) + if (status == 0) + state->start = NULL; + else if (state->ptr != state->start) + state->start = state->ptr; + else if (state->ptr != state->end) state->start = (void*) ((char*) state->ptr + state->charsize); else - state->start = state->ptr; + state->start = NULL; return match; } @@ -2594,6 +2603,9 @@ PyObject* match; Py_ssize_t status; + if (state->start == NULL) + Py_RETURN_NONE; + state_reset(state); state->ptr = state->start; @@ -2605,10 +2617,14 @@ match = pattern_new_match((PatternObject*) self->pattern, state, status); - if (status == 0 || state->ptr == state->start) + if (status == 0) + state->start = NULL; + else if (state->ptr != state->start) + state->start = state->ptr; + else if (state->ptr != state->end) state->start = (void*) ((char*) state->ptr + state->charsize); else - state->start = state->ptr; + state->start = NULL; return match; } diff --git a/Modules/sre_lib.h b/Modules/sre_lib.h --- a/Modules/sre_lib.h +++ b/Modules/sre_lib.h @@ -30,7 +30,7 @@ SRE_IS_LINEBREAK((int) ptr[-1])); case SRE_AT_END: - return (((void*) (ptr+1) == state->end && + return (((SRE_CHAR *)state->end - ptr == 1 && SRE_IS_LINEBREAK((int) ptr[0])) || ((void*) ptr == state->end)); @@ -1109,9 +1109,9 @@ /* */ TRACE(("|%p|%p|ASSERT %d\n", ctx->pattern, ctx->ptr, ctx->pattern[1])); + if (ctx->ptr - (SRE_CHAR *)state->beginning < (Py_ssize_t)ctx->pattern[1]) + RETURN_FAILURE; state->ptr = ctx->ptr - ctx->pattern[1]; - if (state->ptr < state->beginning) - RETURN_FAILURE; DO_JUMP0(JUMP_ASSERT, jump_assert, ctx->pattern+2); RETURN_ON_FAILURE(ret); ctx->pattern += ctx->pattern[0]; @@ -1122,8 +1122,8 @@ /* */ TRACE(("|%p|%p|ASSERT_NOT %d\n", ctx->pattern, ctx->ptr, ctx->pattern[1])); - state->ptr = ctx->ptr - ctx->pattern[1]; - if (state->ptr >= state->beginning) { + if (ctx->ptr - (SRE_CHAR *)state->beginning >= (Py_ssize_t)ctx->pattern[1]) { + state->ptr = ctx->ptr - ctx->pattern[1]; DO_JUMP0(JUMP_ASSERT_NOT, jump_assert_not, ctx->pattern+2); if (ret) { RETURN_ON_ERROR(ret); @@ -1215,12 +1215,20 @@ SRE_CODE* overlap = NULL; int flags = 0; + if (ptr > end) + return 0; + if (pattern[0] == SRE_OP_INFO) { /* optimization info block */ /* <1=skip> <2=flags> <3=min> <4=max> <5=prefix info> */ flags = pattern[2]; + if (pattern[3] && end - ptr < (Py_ssize_t)pattern[3]) { + TRACE(("reject (got %u chars, need %u)\n", + (unsigned int)(end - ptr), pattern[3])); + return 0; + } if (pattern[3] > 1) { /* adjust end point (but make sure we leave at least one character in there, so literal search will work) */ @@ -1339,15 +1347,18 @@ break; ptr++; } - } else + } else { /* general case */ - while (ptr <= end) { + assert(ptr <= end); + while (1) { TRACE(("|%p|%p|SEARCH\n", pattern, ptr)); - state->start = state->ptr = ptr++; + state->start = state->ptr = ptr; status = SRE(match)(state, pattern, 0); - if (status != 0) + if (status != 0 || ptr >= end) break; + ptr++; } + } return status; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 13:23:59 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 06 Jul 2015 11:23:59 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4Njg0?= =?utf-8?q?=3A_Fixed_reading_out_of_the_buffer_in_the_re_module=2E?= Message-ID: <20150706112356.103090.9446@psf.io> https://hg.python.org/cpython/rev/0007031e0452 changeset: 96848:0007031e0452 branch: 2.7 parent: 96844:372aa98eb72e user: Serhiy Storchaka date: Mon Jul 06 13:58:24 2015 +0300 summary: Issue #18684: Fixed reading out of the buffer in the re module. files: Misc/NEWS | 2 + Modules/_sre.c | 55 ++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,8 @@ Library ------- +- Issue #18684: Fixed reading out of the buffer in the re module. + - Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment. diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -351,7 +351,7 @@ SRE_IS_LINEBREAK((int) ptr[-1])); case SRE_AT_END: - return (((void*) (ptr+1) == state->end && + return (((SRE_CHAR *)state->end - ptr == 1 && SRE_IS_LINEBREAK((int) ptr[0])) || ((void*) ptr == state->end)); @@ -1404,9 +1404,9 @@ /* */ TRACE(("|%p|%p|ASSERT %d\n", ctx->pattern, ctx->ptr, ctx->pattern[1])); + if (ctx->ptr - (SRE_CHAR *)state->beginning < (Py_ssize_t)ctx->pattern[1]) + RETURN_FAILURE; state->ptr = ctx->ptr - ctx->pattern[1]; - if (state->ptr < state->beginning) - RETURN_FAILURE; DO_JUMP(JUMP_ASSERT, jump_assert, ctx->pattern+2); RETURN_ON_FAILURE(ret); ctx->pattern += ctx->pattern[0]; @@ -1417,8 +1417,8 @@ /* */ TRACE(("|%p|%p|ASSERT_NOT %d\n", ctx->pattern, ctx->ptr, ctx->pattern[1])); - state->ptr = ctx->ptr - ctx->pattern[1]; - if (state->ptr >= state->beginning) { + if (ctx->ptr - (SRE_CHAR *)state->beginning >= (Py_ssize_t)ctx->pattern[1]) { + state->ptr = ctx->ptr - ctx->pattern[1]; DO_JUMP(JUMP_ASSERT_NOT, jump_assert_not, ctx->pattern+2); if (ret) { RETURN_ON_ERROR(ret); @@ -1510,12 +1510,20 @@ SRE_CODE* overlap = NULL; int flags = 0; + if (ptr > end) + return 0; + if (pattern[0] == SRE_OP_INFO) { /* optimization info block */ /* <1=skip> <2=flags> <3=min> <4=max> <5=prefix info> */ flags = pattern[2]; + if (pattern[3] && end - ptr < (Py_ssize_t)pattern[3]) { + TRACE(("reject (got %u chars, need %u)\n", + (unsigned int)(end - ptr), pattern[3])); + return 0; + } if (pattern[3] > 1) { /* adjust end point (but make sure we leave at least one character in there, so literal search will work) */ @@ -1614,15 +1622,18 @@ break; ptr++; } - } else + } else { /* general case */ - while (ptr <= end) { + assert(ptr <= end); + while (1) { TRACE(("|%p|%p|SEARCH\n", pattern, ptr)); - state->start = state->ptr = ptr++; + state->start = state->ptr = ptr; status = SRE_MATCH(state, pattern); - if (status != 0) + if (status != 0 || ptr >= end) break; + ptr++; } + } return status; } @@ -2295,7 +2306,7 @@ } if (state.start == state.ptr) { - if (last == state.end) + if (last == state.end || state.ptr == state.end) break; /* skip one character */ state.start = (void*) ((char*) state.ptr + state.charsize); @@ -2497,6 +2508,8 @@ next: /* move on */ + if (state.ptr == state.end) + break; if (state.ptr == state.start) state.start = (void*) ((char*) state.ptr + state.charsize); else @@ -3843,6 +3856,9 @@ PyObject* match; int status; + if (state->start == NULL) + Py_RETURN_NONE; + state_reset(state); state->ptr = state->start; @@ -3860,10 +3876,14 @@ match = pattern_new_match((PatternObject*) self->pattern, state, status); - if (status == 0 || state->ptr == state->start) + if (status == 0) + state->start = NULL; + else if (state->ptr != state->start) + state->start = state->ptr; + else if (state->ptr != state->end) state->start = (void*) ((char*) state->ptr + state->charsize); else - state->start = state->ptr; + state->start = NULL; return match; } @@ -3876,6 +3896,9 @@ PyObject* match; int status; + if (state->start == NULL) + Py_RETURN_NONE; + state_reset(state); state->ptr = state->start; @@ -3893,10 +3916,14 @@ match = pattern_new_match((PatternObject*) self->pattern, state, status); - if (status == 0 || state->ptr == state->start) + if (status == 0) + state->start = NULL; + else if (state->ptr != state->start) + state->start = state->ptr; + else if (state->ptr != state->end) state->start = (void*) ((char*) state->ptr + state->charsize); else - state->start = state->ptr; + state->start = NULL; return match; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 16:41:40 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 06 Jul 2015 14:41:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_tighten_warnin?= =?utf-8?q?g?= Message-ID: <20150706144140.6282.18948@psf.io> https://hg.python.org/cpython/rev/0a849e812332 changeset: 96853:0a849e812332 branch: 2.7 parent: 96848:0007031e0452 user: Benjamin Peterson date: Mon Jul 06 09:40:43 2015 -0500 summary: tighten warning files: Doc/library/pickle.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -27,9 +27,9 @@ .. warning:: - The :mod:`pickle` module is not intended to be secure against erroneous or - maliciously constructed data. Never unpickle data received from an untrusted - or unauthenticated source. + The :mod:`pickle` module is secure against erroneous or maliciously + constructed data. Never unpickle data received from an untrusted or + unauthenticated source. Relationship to other Python modules -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 16:41:40 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 06 Jul 2015 14:41:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy41?= Message-ID: <20150706144140.14890.67260@psf.io> https://hg.python.org/cpython/rev/31015ca8091a changeset: 96855:31015ca8091a parent: 96851:bb9fc884a838 parent: 96854:4e81960d89aa user: Benjamin Peterson date: Mon Jul 06 09:41:20 2015 -0500 summary: merge 3.5 files: Doc/library/pickle.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -26,9 +26,9 @@ .. warning:: - The :mod:`pickle` module is not intended to be secure against erroneous or - maliciously constructed data. Never unpickle data received from an untrusted - or unauthenticated source. + The :mod:`pickle` module is secure against erroneous or maliciously + constructed data. Never unpickle data received from an untrusted or + unauthenticated source. Relationship to other Python modules -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 16:41:40 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 06 Jul 2015 14:41:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_tighten_warnin?= =?utf-8?q?g?= Message-ID: <20150706144140.9720.87678@psf.io> https://hg.python.org/cpython/rev/94e0b89591ff changeset: 96852:94e0b89591ff branch: 3.4 parent: 96849:389795b7c703 user: Benjamin Peterson date: Mon Jul 06 09:40:43 2015 -0500 summary: tighten warning files: Doc/library/pickle.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -26,9 +26,9 @@ .. warning:: - The :mod:`pickle` module is not intended to be secure against erroneous or - maliciously constructed data. Never unpickle data received from an untrusted - or unauthenticated source. + The :mod:`pickle` module is secure against erroneous or maliciously + constructed data. Never unpickle data received from an untrusted or + unauthenticated source. Relationship to other Python modules -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 16:41:44 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 06 Jul 2015 14:41:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_merge_3=2E4?= Message-ID: <20150706144140.7742.69780@psf.io> https://hg.python.org/cpython/rev/4e81960d89aa changeset: 96854:4e81960d89aa branch: 3.5 parent: 96850:5adf995d443f parent: 96852:94e0b89591ff user: Benjamin Peterson date: Mon Jul 06 09:41:07 2015 -0500 summary: merge 3.4 files: Doc/library/pickle.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -26,9 +26,9 @@ .. warning:: - The :mod:`pickle` module is not intended to be secure against erroneous or - maliciously constructed data. Never unpickle data received from an untrusted - or unauthenticated source. + The :mod:`pickle` module is secure against erroneous or maliciously + constructed data. Never unpickle data received from an untrusted or + unauthenticated source. Relationship to other Python modules -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 17:53:56 2015 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 06 Jul 2015 15:53:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Tighten-up_code_in_set=5Fn?= =?utf-8?q?ext=28=29_to_use_an_entry_pointer_rather_than_indexing=2E?= Message-ID: <20150706154342.28324.37557@psf.io> https://hg.python.org/cpython/rev/e0b398869e16 changeset: 96856:e0b398869e16 user: Raymond Hettinger date: Mon Jul 06 08:43:37 2015 -0700 summary: Tighten-up code in set_next() to use an entry pointer rather than indexing. files: Objects/setobject.c | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -518,20 +518,22 @@ { Py_ssize_t i; Py_ssize_t mask; - setentry *table; + setentry *entry; assert (PyAnySet_Check(so)); i = *pos_ptr; assert(i >= 0); - table = so->table; mask = so->mask; - while (i <= mask && (table[i].key == NULL || table[i].key == dummy)) + entry = &so->table[i]; + while (i <= mask && (entry->key == NULL || entry->key == dummy)) { i++; + entry++; + } *pos_ptr = i+1; if (i > mask) return 0; - assert(table[i].key != NULL); - *entry_ptr = &table[i]; + assert(entry != NULL); + *entry_ptr = entry; return 1; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 18:29:06 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 06 Jul 2015 16:29:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogJ25vdCcgaXMgdmVy?= =?utf-8?q?y_important_here?= Message-ID: <20150706162906.15330.78802@psf.io> https://hg.python.org/cpython/rev/80e28c4ed30b changeset: 96858:80e28c4ed30b branch: 2.7 parent: 96853:0a849e812332 user: Benjamin Peterson date: Mon Jul 06 11:28:07 2015 -0500 summary: 'not' is very important here files: Doc/library/pickle.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -27,7 +27,7 @@ .. warning:: - The :mod:`pickle` module is secure against erroneous or maliciously + The :mod:`pickle` module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 18:29:08 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 06 Jul 2015 16:29:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy41?= Message-ID: <20150706162906.12463.61676@psf.io> https://hg.python.org/cpython/rev/8681d2fa6a4d changeset: 96860:8681d2fa6a4d parent: 96856:e0b398869e16 parent: 96859:5adb9e5c2d9b user: Benjamin Peterson date: Mon Jul 06 11:28:47 2015 -0500 summary: merge 3.5 files: Doc/library/pickle.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -26,7 +26,7 @@ .. warning:: - The :mod:`pickle` module is secure against erroneous or maliciously + The :mod:`pickle` module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 18:29:08 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 06 Jul 2015 16:29:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_merge_3=2E4?= Message-ID: <20150706162906.29596.96779@psf.io> https://hg.python.org/cpython/rev/5adb9e5c2d9b changeset: 96859:5adb9e5c2d9b branch: 3.5 parent: 96854:4e81960d89aa parent: 96857:a42dbb9ebda4 user: Benjamin Peterson date: Mon Jul 06 11:28:40 2015 -0500 summary: merge 3.4 files: Doc/library/pickle.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -26,7 +26,7 @@ .. warning:: - The :mod:`pickle` module is secure against erroneous or maliciously + The :mod:`pickle` module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 18:29:08 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 06 Jul 2015 16:29:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogJ25vdCcgaXMgdmVy?= =?utf-8?q?y_important_here?= Message-ID: <20150706162905.116441.24142@psf.io> https://hg.python.org/cpython/rev/a42dbb9ebda4 changeset: 96857:a42dbb9ebda4 branch: 3.4 parent: 96852:94e0b89591ff user: Benjamin Peterson date: Mon Jul 06 11:28:07 2015 -0500 summary: 'not' is very important here files: Doc/library/pickle.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -26,7 +26,7 @@ .. warning:: - The :mod:`pickle` module is secure against erroneous or maliciously + The :mod:`pickle` module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 19:05:28 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 06 Jul 2015 17:05:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Corrected_empt?= =?utf-8?q?y_lines_and_removed_BOM_in_Misc/NEWS=2E?= Message-ID: <20150706170528.7742.78639@psf.io> https://hg.python.org/cpython/rev/4796dec0a7d0 changeset: 96861:4796dec0a7d0 branch: 2.7 parent: 96858:80e28c4ed30b user: Serhiy Storchaka date: Mon Jul 06 19:47:12 2015 +0300 summary: Corrected empty lines and removed BOM in Misc/NEWS. files: Misc/NEWS | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1,4 +1,4 @@ -?+++++++++++ ++++++++++++ Python News +++++++++++ @@ -126,6 +126,7 @@ - Issue #22931: Allow '[' and ']' in cookie values. + What's New in Python 2.7.10 release candidate 1? ================================================ @@ -828,7 +829,6 @@ - Issue #22644: The bundled version of OpenSSL has been updated to 1.0.1j. - What's New in Python 2.7.8? =========================== @@ -981,6 +981,7 @@ - Issue #21671, CVE-2014-0224: The bundled version of OpenSSL has been updated to 1.0.1h. + What's New in Python 2.7.7 ========================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 19:05:28 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 06 Jul 2015 17:05:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Corrected_empty_lines_in_Misc/NEWS=2E?= Message-ID: <20150706170528.130183.13163@psf.io> https://hg.python.org/cpython/rev/78dc519d055c changeset: 96863:78dc519d055c branch: 3.5 parent: 96859:5adb9e5c2d9b parent: 96862:4fee906b9e9e user: Serhiy Storchaka date: Mon Jul 06 20:02:50 2015 +0300 summary: Corrected empty lines in Misc/NEWS. files: Misc/NEWS | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -626,7 +626,6 @@ - Issue #23310: Fix MagicMock's initializer to work with __methods__, just like configure_mock(). Patch by Kasia Jachim. - Build ----- @@ -1624,6 +1623,7 @@ - Issue #23392: Added tests for marshal C API that works with FILE*. + - Issue #10510: distutils register and upload methods now use HTML standards compliant CRLF line endings. @@ -2812,6 +2812,7 @@ - Issue #22980: .pyd files with a version and platform tag (for example, ".cp35-win32.pyd") will now be loaded in preference to those without tags. + What's New in Python 3.4.0? =========================== @@ -3447,6 +3448,7 @@ - Issue #12837: Silence a tautological comparison warning on OS X under Clang in socketmodule.c. + What's New in Python 3.4.0 Beta 2? ================================== @@ -3822,6 +3824,7 @@ - Issue #19976: Argument Clinic METH_NOARGS functions now always take two parameters. + What's New in Python 3.4.0 Beta 1? ================================== @@ -4292,6 +4295,7 @@ - Issue #19390: Argument Clinic no longer accepts malformed Python and C ids. + What's New in Python 3.4.0 Alpha 4? =================================== @@ -4521,6 +4525,7 @@ options like -fwrapv were overridden and thus not used, which could result in broken interpreters when building with clang. + What's New in Python 3.4.0 Alpha 3? =================================== @@ -4905,6 +4910,7 @@ - Issue #18922: Now The Lib/smtpd.py and Tools/i18n/msgfmt.py scripts write their version strings to stdout, and not to sderr. + What's New in Python 3.4.0 Alpha 1? =================================== @@ -5474,6 +5480,7 @@ when \r\n appears at end of 65535 bytes without other newlines. - Issue #18076: Introduce importlib.util.decode_source(). + - Issue #18357: add tests for dictview set difference. Patch by Fraser Tweedale. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 19:05:28 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 06 Jul 2015 17:05:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Corrected_empt?= =?utf-8?q?y_lines_in_Misc/NEWS=2E?= Message-ID: <20150706170528.29384.55681@psf.io> https://hg.python.org/cpython/rev/4fee906b9e9e changeset: 96862:4fee906b9e9e branch: 3.4 parent: 96857:a42dbb9ebda4 user: Serhiy Storchaka date: Mon Jul 06 19:58:11 2015 +0300 summary: Corrected empty lines in Misc/NEWS. files: Misc/NEWS | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -778,14 +778,12 @@ - Issue #22644: The bundled version of OpenSSL has been updated to 1.0.1j. + What's New in Python 3.4.2? =========================== Release date: 2014-10-06 -Core and Builtins ------------------ - Library ------- @@ -1523,6 +1521,7 @@ ----------------- - Issue #21276: posixmodule: Don't define USE_XATTRS on KFreeBSD and the Hurd. + - Issue #21226: Set up modules properly in PyImport_ExecCodeModuleObject (and friends). @@ -2259,6 +2258,7 @@ - Issue #12837: Silence a tautological comparison warning on OS X under Clang in socketmodule.c. + What's New in Python 3.4.0 Beta 2? ================================== @@ -2634,6 +2634,7 @@ - Issue #19976: Argument Clinic METH_NOARGS functions now always take two parameters. + What's New in Python 3.4.0 Beta 1? ================================== @@ -3104,6 +3105,7 @@ - Issue #19390: Argument Clinic no longer accepts malformed Python and C ids. + What's New in Python 3.4.0 Alpha 4? =================================== @@ -3333,6 +3335,7 @@ options like -fwrapv were overridden and thus not used, which could result in broken interpreters when building with clang. + What's New in Python 3.4.0 Alpha 3? =================================== @@ -3717,6 +3720,7 @@ - Issue #18922: Now The Lib/smtpd.py and Tools/i18n/msgfmt.py scripts write their version strings to stdout, and not to sderr. + What's New in Python 3.4.0 Alpha 1? =================================== @@ -4286,6 +4290,7 @@ when \r\n appears at end of 65535 bytes without other newlines. - Issue #18076: Introduce importlib.util.decode_source(). + - Issue #18357: add tests for dictview set difference. Patch by Fraser Tweedale. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Jul 6 19:05:28 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 06 Jul 2015 17:05:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Corrected_empty_lines_in_Misc/NEWS=2E?= Message-ID: <20150706170528.10165.18026@psf.io> https://hg.python.org/cpython/rev/7c74ece3bb16 changeset: 96864:7c74ece3bb16 parent: 96860:8681d2fa6a4d parent: 96863:78dc519d055c user: Serhiy Storchaka date: Mon Jul 06 20:04:21 2015 +0300 summary: Corrected empty lines in Misc/NEWS. files: Misc/NEWS | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -645,7 +645,6 @@ - Issue #23310: Fix MagicMock's initializer to work with __methods__, just like configure_mock(). Patch by Kasia Jachim. - Build ----- @@ -1643,6 +1642,7 @@ - Issue #23392: Added tests for marshal C API that works with FILE*. + - Issue #10510: distutils register and upload methods now use HTML standards compliant CRLF line endings. @@ -2831,6 +2831,7 @@ - Issue #22980: .pyd files with a version and platform tag (for example, ".cp35-win32.pyd") will now be loaded in preference to those without tags. + What's New in Python 3.4.0? =========================== @@ -3466,6 +3467,7 @@ - Issue #12837: Silence a tautological comparison warning on OS X under Clang in socketmodule.c. + What's New in Python 3.4.0 Beta 2? ================================== @@ -3841,6 +3843,7 @@ - Issue #19976: Argument Clinic METH_NOARGS functions now always take two parameters. + What's New in Python 3.4.0 Beta 1? ================================== @@ -4311,6 +4314,7 @@ - Issue #19390: Argument Clinic no longer accepts malformed Python and C ids. + What's New in Python 3.4.0 Alpha 4? =================================== @@ -4540,6 +4544,7 @@ options like -fwrapv were overridden and thus not used, which could result in broken interpreters when building with clang. + What's New in Python 3.4.0 Alpha 3? =================================== @@ -4924,6 +4929,7 @@ - Issue #18922: Now The Lib/smtpd.py and Tools/i18n/msgfmt.py scripts write their version strings to stdout, and not to sderr. + What's New in Python 3.4.0 Alpha 1? =================================== @@ -5493,6 +5499,7 @@ when \r\n appears at end of 65535 bytes without other newlines. - Issue #18076: Introduce importlib.util.decode_source(). + - Issue #18357: add tests for dictview set difference. Patch by Fraser Tweedale. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 04:03:07 2015 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 07 Jul 2015 02:03:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Tighten-up_code_in_the_set?= =?utf-8?q?_iterator_to_use_an_entry_pointer_rather_than?= Message-ID: <20150707020307.11325.89553@psf.io> https://hg.python.org/cpython/rev/c9782a9ac031 changeset: 96865:c9782a9ac031 user: Raymond Hettinger date: Mon Jul 06 19:03:01 2015 -0700 summary: Tighten-up code in the set iterator to use an entry pointer rather than indexing. files: Objects/setobject.c | 35 ++++++++++++-------------------- 1 files changed, 13 insertions(+), 22 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -766,8 +766,8 @@ PyObject_HEAD PySetObject *si_set; /* Set to NULL when iterator is exhausted */ Py_ssize_t si_used; - Py_ssize_t si_pos; Py_ssize_t len; + setentry *entry; } setiterobject; static void @@ -845,8 +845,6 @@ static PyObject *setiter_iternext(setiterobject *si) { - PyObject *key; - Py_ssize_t i, mask; setentry *entry; PySetObject *so = si->si_set; @@ -860,25 +858,18 @@ si->si_used = -1; /* Make this state sticky */ return NULL; } - - i = si->si_pos; - assert(i>=0); - entry = so->table; - mask = so->mask; - while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) - i++; - si->si_pos = i+1; - if (i > mask) - goto fail; + if (si->len <= 0) { + Py_DECREF(so); + si->si_set = NULL; + return NULL; + } + entry = si->entry; + while (entry->key == NULL || entry->key == dummy) + entry++; si->len--; - key = entry[i].key; - Py_INCREF(key); - return key; - -fail: - Py_DECREF(so); - si->si_set = NULL; - return NULL; + si->entry = entry + 1; + Py_INCREF(entry->key); + return entry->key; } PyTypeObject PySetIter_Type = { @@ -923,8 +914,8 @@ Py_INCREF(so); si->si_set = so; si->si_used = so->used; - si->si_pos = 0; si->len = so->used; + si->entry = so->table; _PyObject_GC_TRACK(si); return (PyObject *)si; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 04:08:53 2015 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 07 Jul 2015 02:08:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_bit_of_factoring-out?= =?utf-8?q?_common_code=2E?= Message-ID: <20150707020853.20885.2805@psf.io> https://hg.python.org/cpython/rev/5088f2cd6293 changeset: 96866:5088f2cd6293 user: Raymond Hettinger date: Mon Jul 06 19:08:49 2015 -0700 summary: Minor bit of factoring-out common code. files: Objects/setobject.c | 29 +++++++++++------------------ 1 files changed, 11 insertions(+), 18 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1271,26 +1271,14 @@ while ((key = PyIter_Next(it)) != NULL) { hash = PyObject_Hash(key); - if (hash == -1) { - Py_DECREF(it); - Py_DECREF(result); - Py_DECREF(key); - return NULL; - } + if (hash == -1) + goto error; rv = set_contains_entry(so, key, hash); - if (rv < 0) { - Py_DECREF(it); - Py_DECREF(result); - Py_DECREF(key); - return NULL; - } + if (rv < 0) + goto error; if (rv) { - if (set_add_entry(result, key, hash)) { - Py_DECREF(it); - Py_DECREF(result); - Py_DECREF(key); - return NULL; - } + if (set_add_entry(result, key, hash)) + goto error; } Py_DECREF(key); } @@ -1300,6 +1288,11 @@ return NULL; } return (PyObject *)result; + error: + Py_DECREF(it); + Py_DECREF(result); + Py_DECREF(key); + return NULL; } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 06:33:43 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 04:33:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Merge_3=2E4?= Message-ID: <20150707043343.27420.64626@psf.io> https://hg.python.org/cpython/rev/74b1a0001dc8 changeset: 96868:74b1a0001dc8 branch: 3.5 parent: 96863:78dc519d055c parent: 96867:0f5a57b822c2 user: Zachary Ware date: Mon Jul 06 23:30:16 2015 -0500 summary: Merge 3.4 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 06:33:43 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 04:33:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41?= Message-ID: <20150707043343.44850.65081@psf.io> https://hg.python.org/cpython/rev/91681c1524da changeset: 96869:91681c1524da parent: 96866:5088f2cd6293 parent: 96868:74b1a0001dc8 user: Zachary Ware date: Mon Jul 06 23:33:33 2015 -0500 summary: Merge 3.5 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 06:33:43 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 04:33:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_suspicious?= =?utf-8?q?_markup?= Message-ID: <20150707043343.130183.13462@psf.io> https://hg.python.org/cpython/rev/0f5a57b822c2 changeset: 96867:0f5a57b822c2 branch: 3.4 parent: 96862:4fee906b9e9e user: Zachary Ware date: Mon Jul 06 23:27:15 2015 -0500 summary: Fix suspicious markup files: Doc/c-api/structures.rst | 2 +- Doc/library/unittest.mock.rst | 2 +- Doc/tools/susp-ignored.csv | 15 ++++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -44,7 +44,7 @@ PyObject ob_base; - See documentation of :c:type::`PyObject` above. + See documentation of :c:type:`PyObject` above. .. c:macro:: PyObject_VAR_HEAD diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -1587,7 +1587,7 @@ * Context manager: ``__enter__`` and ``__exit__`` * Unary numeric methods: ``__neg__``, ``__pos__`` and ``__invert__`` * The numeric methods (including right hand and in-place variants): - ``__add__``, ``__sub__``, ``__mul__``, ``__div__``,``__truediv__``, + ``__add__``, ``__sub__``, ``__mul__``, ``__div__``, ``__truediv__``, ``__floordiv__``, ``__mod__``, ``__divmod__``, ``__lshift__``, ``__rshift__``, ``__and__``, ``__xor__``, ``__or__``, and ``__pow__`` * Numeric conversion methods: ``__complex__``, ``__int__``, ``__float__`` diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -136,12 +136,11 @@ library/ipaddress,,::,2001:db00::0/ffff:ff00:: library/itertools,,:step,elements from seq[start:stop:step] library/itertools,,:stop,elements from seq[start:stop:step] -library/linecache,,:sys,"sys:x:3:3:sys:/dev:/bin/sh" library/logging.handlers,,:port,host:port library/mmap,,:i2,obj[i1:i2] library/multiprocessing,,`,# Add more tasks using `put()` library/multiprocessing,,`,">>> l._callmethod('__getitem__', (20,)) # equiv to `l[20]`" -library/multiprocessing,,`,">>> l._callmethod('__getslice__', (2, 7)) # equiv to `l[2:7]`" +library/multiprocessing,,`,">>> l._callmethod('__getitem__', (slice(2, 7),)) # equiv to `l[2:7]`" library/multiprocessing,,:queue,">>> QueueManager.register('get_queue', callable=lambda:queue)" library/multiprocessing,,`,# register the Foo class; make `f()` and `g()` accessible via proxy library/multiprocessing,,`,# register the Foo class; make `g()` and `_h()` accessible via proxy @@ -164,7 +163,6 @@ library/pyexpat,,:elem1, library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">" library/smtplib,,:port,method must support that as well as a regular host:port -library/socket,,::,"(10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0))]" library/socket,,::,'5aef:2b::8' library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" library/socket,,:len,fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) @@ -210,6 +208,16 @@ library/venv,,:param,":param progress: If setuptools or pip are installed, the progress of the" library/venv,,:param,":param nopip: If True, pip is not installed into the created" library/venv,,:param,:param context: The information for the environment creation request +library/xml.etree.elementtree,,:sometag,prefix:sometag +library/xml.etree.elementtree,,:fictional,"Lancelot +library/xml.etree.elementtree,,:character,Archie Leach +library/xml.etree.elementtree,,:character,Sir Robin +library/xml.etree.elementtree,,:character,Gunther +library/xml.etree.elementtree,,:character,Commander Clement +library/xml.etree.elementtree,,:actor,"for actor in root.findall('real_person:actor', ns):" +library/xml.etree.elementtree,,:name,"name = actor.find('real_person:name', ns)" +library/xml.etree.elementtree,,:character,"for char in actor.findall('role:character', ns):" library/xmlrpc.client,,:pass,http://user:pass at host:port/path library/xmlrpc.client,,:pass,user:pass library/xmlrpc.client,,:port,http://user:pass at host:port/path @@ -236,6 +244,7 @@ tutorial/stdlib2,,:start,"fields = struct.unpack(' https://hg.python.org/cpython/rev/938fe6ce92a7 changeset: 96871:938fe6ce92a7 branch: 3.5 parent: 96868:74b1a0001dc8 parent: 96870:ed6ec65f50d2 user: Zachary Ware date: Tue Jul 07 00:00:43 2015 -0500 summary: Merge 3.4 files: Doc/c-api/structures.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -60,7 +60,7 @@ .. c:macro:: Py_TYPE(o) - This macro is used to access the `ob_type` member of a Python object. + This macro is used to access the :attr:`ob_type` member of a Python object. It expands to:: (((PyObject*)(o))->ob_type) @@ -68,7 +68,8 @@ .. c:macro:: Py_REFCNT(o) - This macro is used to access the `ob_refcnt` member of a Python object. + This macro is used to access the :attr:`ob_refcnt` member of a Python + object. It expands to:: (((PyObject*)(o))->ob_refcnt) @@ -76,7 +77,7 @@ .. c:macro:: Py_SIZE(o) - This macro is used to access the `ob_size` member of a Python object. + This macro is used to access the :attr:`ob_size` member of a Python object. It expands to:: (((PyVarObject*)(o))->ob_size) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 07:11:57 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 05:11:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Fix_usage_of_t?= =?utf-8?q?he_default_role=2E?= Message-ID: <20150707051157.108523.55641@psf.io> https://hg.python.org/cpython/rev/39d7b41c04f6 changeset: 96872:39d7b41c04f6 branch: 3.5 user: Zachary Ware date: Tue Jul 07 00:07:25 2015 -0500 summary: Fix usage of the default role. files: Doc/library/sys.rst | 2 +- Doc/library/test.rst | 6 +++--- Doc/whatsnew/3.5.rst | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1100,7 +1100,7 @@ pass # The following line will fail with a RuntimeError, because - # `wrapper` creates a `wrap(coro)` coroutine: + # ``wrapper`` creates a ``wrap(coro)`` coroutine: foo() See also :func:`get_coroutine_wrapper`. diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -570,9 +570,9 @@ .. function:: detect_api_mismatch(ref_api, other_api, *, ignore=()): - Returns the set of attributes, functions or methods of `ref_api` not - found on `other_api`, except for a defined list of items to be - ignored in this check specified in `ignore`. + Returns the set of attributes, functions or methods of *ref_api* not + found on *other_api*, except for a defined list of items to be + ignored in this check specified in *ignore*. By default this skips private attributes beginning with '_' but includes all magic methods, i.e. those starting and ending in '__'. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -1086,7 +1086,7 @@ * The :mod:`socket` module now exports the CAN_RAW_FD_FRAMES constant on linux 3.6 and greater. -* The `pygettext.py` Tool now uses the standard +NNNN format for timezones in +* The ``pygettext.py`` Tool now uses the standard +NNNN format for timezones in the POT-Creation-Date header. * The :mod:`smtplib` module now uses :data:`sys.stderr` instead of previous -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 07:11:57 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 05:11:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41?= Message-ID: <20150707051157.15517.45779@psf.io> https://hg.python.org/cpython/rev/87853f158042 changeset: 96873:87853f158042 parent: 96869:91681c1524da parent: 96872:39d7b41c04f6 user: Zachary Ware date: Tue Jul 07 00:08:50 2015 -0500 summary: Merge 3.5 files: Doc/c-api/structures.rst | 7 ++++--- Doc/library/sys.rst | 2 +- Doc/library/test.rst | 6 +++--- Doc/whatsnew/3.5.rst | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -60,7 +60,7 @@ .. c:macro:: Py_TYPE(o) - This macro is used to access the `ob_type` member of a Python object. + This macro is used to access the :attr:`ob_type` member of a Python object. It expands to:: (((PyObject*)(o))->ob_type) @@ -68,7 +68,8 @@ .. c:macro:: Py_REFCNT(o) - This macro is used to access the `ob_refcnt` member of a Python object. + This macro is used to access the :attr:`ob_refcnt` member of a Python + object. It expands to:: (((PyObject*)(o))->ob_refcnt) @@ -76,7 +77,7 @@ .. c:macro:: Py_SIZE(o) - This macro is used to access the `ob_size` member of a Python object. + This macro is used to access the :attr:`ob_size` member of a Python object. It expands to:: (((PyVarObject*)(o))->ob_size) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1100,7 +1100,7 @@ pass # The following line will fail with a RuntimeError, because - # `wrapper` creates a `wrap(coro)` coroutine: + # ``wrapper`` creates a ``wrap(coro)`` coroutine: foo() See also :func:`get_coroutine_wrapper`. diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -570,9 +570,9 @@ .. function:: detect_api_mismatch(ref_api, other_api, *, ignore=()): - Returns the set of attributes, functions or methods of `ref_api` not - found on `other_api`, except for a defined list of items to be - ignored in this check specified in `ignore`. + Returns the set of attributes, functions or methods of *ref_api* not + found on *other_api*, except for a defined list of items to be + ignored in this check specified in *ignore*. By default this skips private attributes beginning with '_' but includes all magic methods, i.e. those starting and ending in '__'. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -1086,7 +1086,7 @@ * The :mod:`socket` module now exports the CAN_RAW_FD_FRAMES constant on linux 3.6 and greater. -* The `pygettext.py` Tool now uses the standard +NNNN format for timezones in +* The ``pygettext.py`` Tool now uses the standard +NNNN format for timezones in the POT-Creation-Date header. * The :mod:`smtplib` module now uses :data:`sys.stderr` instead of previous -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 07:11:57 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 05:11:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_usage_of_t?= =?utf-8?q?he_default_role=2E?= Message-ID: <20150707051157.102195.56679@psf.io> https://hg.python.org/cpython/rev/ed6ec65f50d2 changeset: 96870:ed6ec65f50d2 branch: 3.4 parent: 96867:0f5a57b822c2 user: Zachary Ware date: Mon Jul 06 23:58:12 2015 -0500 summary: Fix usage of the default role. The changes to Doc/library/unittest.mock.rst are almost entirely a selective backport of the 3.5 page. files: Doc/c-api/structures.rst | 7 +- Doc/library/unittest.mock.rst | 86 +++++++++++----------- 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -60,7 +60,7 @@ .. c:macro:: Py_TYPE(o) - This macro is used to access the `ob_type` member of a Python object. + This macro is used to access the :attr:`ob_type` member of a Python object. It expands to:: (((PyObject*)(o))->ob_type) @@ -68,7 +68,8 @@ .. c:macro:: Py_REFCNT(o) - This macro is used to access the `ob_refcnt` member of a Python object. + This macro is used to access the :attr:`ob_refcnt` member of a Python + object. It expands to:: (((PyObject*)(o))->ob_refcnt) @@ -76,7 +77,7 @@ .. c:macro:: Py_SIZE(o) - This macro is used to access the `ob_size` member of a Python object. + This macro is used to access the :attr:`ob_size` member of a Python object. It expands to:: (((PyVarObject*)(o))->ob_size) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -181,71 +181,71 @@ -------------- -`Mock` is a flexible mock object intended to replace the use of stubs and +:class:`Mock` is a flexible mock object intended to replace the use of stubs and test doubles throughout your code. Mocks are callable and create attributes as new mocks when you access them [#]_. Accessing the same attribute will always return the same mock. Mocks record how you use them, allowing you to make assertions about what your code has done to them. -:class:`MagicMock` is a subclass of `Mock` with all the magic methods +:class:`MagicMock` is a subclass of :class:`Mock` with all the magic methods pre-created and ready to use. There are also non-callable variants, useful when you are mocking out objects that aren't callable: :class:`NonCallableMock` and :class:`NonCallableMagicMock` The :func:`patch` decorators makes it easy to temporarily replace classes -in a particular module with a `Mock` object. By default `patch` will create -a `MagicMock` for you. You can specify an alternative class of `Mock` using -the `new_callable` argument to `patch`. +in a particular module with a :class:`Mock` object. By default :func:`patch` will create +a :class:`MagicMock` for you. You can specify an alternative class of :class:`Mock` using +the *new_callable* argument to :func:`patch`. .. class:: Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, **kwargs) - Create a new `Mock` object. `Mock` takes several optional arguments + Create a new :class:`Mock` object. :class:`Mock` takes several optional arguments that specify the behaviour of the Mock object: - * `spec`: This can be either a list of strings or an existing object (a + * *spec*: This can be either a list of strings or an existing object (a class or instance) that acts as the specification for the mock object. If you pass in an object then a list of strings is formed by calling dir on the object (excluding unsupported magic attributes and methods). - Accessing any attribute not in this list will raise an `AttributeError`. - - If `spec` is an object (rather than a list of strings) then + Accessing any attribute not in this list will raise an :exc:`AttributeError`. + + If *spec* is an object (rather than a list of strings) then :attr:`~instance.__class__` returns the class of the spec object. This - allows mocks to pass `isinstance` tests. - - * `spec_set`: A stricter variant of `spec`. If used, attempting to *set* + allows mocks to pass :func:`isinstance` tests. + + * *spec_set*: A stricter variant of *spec*. If used, attempting to *set* or get an attribute on the mock that isn't on the object passed as - `spec_set` will raise an `AttributeError`. - - * `side_effect`: A function to be called whenever the Mock is called. See + *spec_set* will raise an :exc:`AttributeError`. + + * *side_effect*: A function to be called whenever the Mock is called. See the :attr:`~Mock.side_effect` attribute. Useful for raising exceptions or dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns :data:`DEFAULT`, the return value of this function is used as the return value. - Alternatively `side_effect` can be an exception class or instance. In + Alternatively *side_effect* can be an exception class or instance. In this case the exception will be raised when the mock is called. - If `side_effect` is an iterable then each call to the mock will return + If *side_effect* is an iterable then each call to the mock will return the next value from the iterable. - A `side_effect` can be cleared by setting it to `None`. - - * `return_value`: The value returned when the mock is called. By default + A *side_effect* can be cleared by setting it to ``None``. + + * *return_value*: The value returned when the mock is called. By default this is a new Mock (created on first access). See the :attr:`return_value` attribute. - * `wraps`: Item for the mock object to wrap. If `wraps` is not None then + * *wraps*: Item for the mock object to wrap. If *wraps* is not None then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped object (so attempting to access an attribute that doesn't exist will - raise an `AttributeError`). - - If the mock has an explicit `return_value` set then calls are not passed - to the wrapped object and the `return_value` is returned instead. - - * `name`: If the mock has a name then it will be used in the repr of the + raise an :exc:`AttributeError`). + + If the mock has an explicit *return_value* set then calls are not passed + to the wrapped object and the *return_value* is returned instead. + + * *name*: If the mock has a name then it will be used in the repr of the mock. This can be useful for debugging. The name is propagated to child mocks. @@ -1032,25 +1032,25 @@ default because it can be dangerous. With it switched on you can write passing tests against APIs that don't actually exist! - Patch can be used as a `TestCase` class decorator. It works by + Patch can be used as a :class:`TestCase` class decorator. It works by decorating each test method in the class. This reduces the boilerplate - code when your test methods share a common patchings set. `patch` finds - tests by looking for method names that start with `patch.TEST_PREFIX`. - By default this is `test`, which matches the way `unittest` finds tests. - You can specify an alternative prefix by setting `patch.TEST_PREFIX`. + code when your test methods share a common patchings set. :func:`patch` finds + tests by looking for method names that start with ``patch.TEST_PREFIX``. + By default this is ``'test'``, which matches the way :mod:`unittest` finds tests. + You can specify an alternative prefix by setting ``patch.TEST_PREFIX``. Patch can be used as a context manager, with the with statement. Here the patching applies to the indented block after the with statement. If you use "as" then the patched object will be bound to the name after the - "as"; very useful if `patch` is creating a mock object for you. - - `patch` takes arbitrary keyword arguments. These will be passed to - the `Mock` (or `new_callable`) on construction. - - `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are + "as"; very useful if :func:`patch` is creating a mock object for you. + + :func:`patch` takes arbitrary keyword arguments. These will be passed to + the :class:`Mock` (or *new_callable*) on construction. + + ``patch.dict(...)``, ``patch.multiple(...)`` and ``patch.object(...)`` are available for alternate use-cases. -`patch` as function decorator, creating the mock for you and passing it into +:func:`patch` as function decorator, creating the mock for you and passing it into the decorated function: >>> @patch('__main__.SomeClass') @@ -1392,15 +1392,15 @@ ... assert package.module.Class is self.MockClass ... - As an added bonus you no longer need to keep a reference to the `patcher` + As an added bonus you no longer need to keep a reference to the ``patcher`` object. It is also possible to stop all patches which have been started by using -`patch.stopall`. +:func:`patch.stopall`. .. function:: patch.stopall - Stop all active patches. Only stops patches started with `start`. + Stop all active patches. Only stops patches started with ``start``. TEST_PREFIX -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 07:11:57 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 05:11:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Fix_versioncha?= =?utf-8?q?nged_directives?= Message-ID: <20150707051157.8143.94055@psf.io> https://hg.python.org/cpython/rev/60a4a9ea887d changeset: 96874:60a4a9ea887d branch: 3.5 parent: 96872:39d7b41c04f6 user: Zachary Ware date: Tue Jul 07 00:11:36 2015 -0500 summary: Fix versionchanged directives files: Doc/distutils/builtdist.rst | 2 +- Doc/distutils/sourcedist.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -100,7 +100,7 @@ | ``msi`` | Microsoft Installer. | | +-------------+------------------------------+---------+ -.. versionchanged: 3.5 +.. versionchanged:: 3.5 Added support for the ``xztar`` format. diff --git a/Doc/distutils/sourcedist.rst b/Doc/distutils/sourcedist.rst --- a/Doc/distutils/sourcedist.rst +++ b/Doc/distutils/sourcedist.rst @@ -41,7 +41,7 @@ | ``tar`` | tar file (:file:`.tar`) | | +-----------+-------------------------+---------+ -.. versionchanged: 3.5 +.. versionchanged:: 3.5 Added support for the ``xztar`` format. Notes: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 07:11:57 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 05:11:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41?= Message-ID: <20150707051157.30594.78714@psf.io> https://hg.python.org/cpython/rev/ce0bb740d295 changeset: 96875:ce0bb740d295 parent: 96873:87853f158042 parent: 96874:60a4a9ea887d user: Zachary Ware date: Tue Jul 07 00:11:49 2015 -0500 summary: Merge 3.5 files: Doc/distutils/builtdist.rst | 2 +- Doc/distutils/sourcedist.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -100,7 +100,7 @@ | ``msi`` | Microsoft Installer. | | +-------------+------------------------------+---------+ -.. versionchanged: 3.5 +.. versionchanged:: 3.5 Added support for the ``xztar`` format. diff --git a/Doc/distutils/sourcedist.rst b/Doc/distutils/sourcedist.rst --- a/Doc/distutils/sourcedist.rst +++ b/Doc/distutils/sourcedist.rst @@ -41,7 +41,7 @@ | ``tar`` | tar file (:file:`.tar`) | | +-----------+-------------------------+---------+ -.. versionchanged: 3.5 +.. versionchanged:: 3.5 Added support for the ``xztar`` format. Notes: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 07:34:43 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 05:34:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy41?= Message-ID: <20150707053443.79698.51554@psf.io> https://hg.python.org/cpython/rev/2f86a69c3220 changeset: 96877:2f86a69c3220 parent: 96875:ce0bb740d295 parent: 96876:24cb8e3f98de user: Zachary Ware date: Tue Jul 07 00:34:37 2015 -0500 summary: Merge 3.5 files: Doc/tools/susp-ignored.csv | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -289,5 +289,5 @@ library/zipapp,82,:fn,"argument should have the form ""pkg.mod:fn"", where ""pkg.mod"" is a" library/zipapp,155,:callable,"""pkg.module:callable"" and the archive will be run by importing" library/stdtypes,3767,::,>>> m[::2].tolist() -library/sys,1115,`,# `wrapper` creates a `wrap(coro)` coroutine: +library/sys,1115,`,# ``wrapper`` creates a ``wrap(coro)`` coroutine: tutorial/venv,77,:c7b9645a6f35,"Python 3.4.3+ (3.4:c7b9645a6f35+, May 22 2015, 09:31:25)" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Jul 7 07:34:43 2015 From: python-checkins at python.org (zach.ware) Date: Tue, 07 Jul 2015 05:34:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Update_ignored?= =?utf-8?q?_suspicious_markup?= Message-ID: <20150707053443.14247.36174@psf.io> https://hg.python.org/cpython/rev/24cb8e3f98de changeset: 96876:24cb8e3f98de branch: 3.5 parent: 96874:60a4a9ea887d user: Zachary Ware date: Tue Jul 07 00:34:25 2015 -0500 summary: Update ignored suspicious markup files: Doc/tools/susp-ignored.csv | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -289,5 +289,5 @@ library/zipapp,82,:fn,"argument should have the form ""pkg.mod:fn"", where ""pkg.mod"" is a" library/zipapp,155,:callable,"""pkg.module:callable"" and the archive will be run by importing" library/stdtypes,3767,::,>>> m[::2].tolist() -library/sys,1115,`,# `wrapper` creates a `wrap(coro)` coroutine: +library/sys,1115,`,# ``wrapper`` creates a ``wrap(coro)`` coroutine: tutorial/venv,77,:c7b9645a6f35,"Python 3.4.3+ (3.4:c7b9645a6f35+, May 22 2015, 09:31:25)" -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Tue Jul 7 10:44:32 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 07 Jul 2015 08:44:32 +0000 Subject: [Python-checkins] Daily reference leaks (2f86a69c3220): sum=7 Message-ID: <20150707084432.8857.30425@psf.io> results for 2f86a69c3220 on branch "default" -------------------------------------------- test_asyncio leaked [0, 0, 3] memory blocks, sum=3 test_functools leaked [0, 2, 2] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogALCj0R', '--timeout', '7200'] From python-checkins at python.org Wed Jul 8 00:29:30 2015 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 07 Jul 2015 22:29:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_24581=3A_Revert_c978?= =?utf-8?q?2a9ac031_pending_a_stronger_test_for_mutation_during?= Message-ID: <20150707222930.130183.42959@psf.io> https://hg.python.org/cpython/rev/648c9fb3bdf5 changeset: 96878:648c9fb3bdf5 user: Raymond Hettinger date: Tue Jul 07 15:29:24 2015 -0700 summary: Issue 24581: Revert c9782a9ac031 pending a stronger test for mutation during iteration. files: Objects/setobject.c | 35 ++++++++++++++++++++------------ 1 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -766,8 +766,8 @@ PyObject_HEAD PySetObject *si_set; /* Set to NULL when iterator is exhausted */ Py_ssize_t si_used; + Py_ssize_t si_pos; Py_ssize_t len; - setentry *entry; } setiterobject; static void @@ -845,6 +845,8 @@ static PyObject *setiter_iternext(setiterobject *si) { + PyObject *key; + Py_ssize_t i, mask; setentry *entry; PySetObject *so = si->si_set; @@ -858,18 +860,25 @@ si->si_used = -1; /* Make this state sticky */ return NULL; } - if (si->len <= 0) { - Py_DECREF(so); - si->si_set = NULL; - return NULL; - } - entry = si->entry; - while (entry->key == NULL || entry->key == dummy) - entry++; + + i = si->si_pos; + assert(i>=0); + entry = so->table; + mask = so->mask; + while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) + i++; + si->si_pos = i+1; + if (i > mask) + goto fail; si->len--; - si->entry = entry + 1; - Py_INCREF(entry->key); - return entry->key; + key = entry[i].key; + Py_INCREF(key); + return key; + +fail: + Py_DECREF(so); + si->si_set = NULL; + return NULL; } PyTypeObject PySetIter_Type = { @@ -914,8 +923,8 @@ Py_INCREF(so); si->si_set = so; si->si_used = so->used; + si->si_pos = 0; si->len = so->used; - si->entry = so->table; _PyObject_GC_TRACK(si); return (PyObject *)si; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 8 05:48:10 2015 From: python-checkins at python.org (steve.dower) Date: Wed, 08 Jul 2015 03:48:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Closes_24584?= =?utf-8?q?=3A_Windows_installer_incorrectly_detects_CRT_version_on_Window?= =?utf-8?q?s_10?= Message-ID: <20150708034810.13199.81360@psf.io> https://hg.python.org/cpython/rev/60eb61d6fdb4 changeset: 96879:60eb61d6fdb4 branch: 3.5 parent: 96876:24cb8e3f98de user: Steve Dower date: Tue Jul 07 20:47:28 2015 -0700 summary: Closes 24584: Windows installer incorrectly detects CRT version on Windows 10 files: Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp --- a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp +++ b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp @@ -2399,10 +2399,10 @@ return FALSE; } - // Check whether at least CRT v10.0.9924.0 is available. + // Check whether at least CRT v10.0.10137.0 is available. // It should only be installed as a Windows Update package, which means // we don't need to worry about 32-bit/64-bit. - LPCWSTR crtFile = L"api-ms-win-crt-runtime-l1-1-0.dll"; + LPCWSTR crtFile = L"ucrtbase.dll"; DWORD cbVer = GetFileVersionInfoSizeW(crtFile, nullptr); if (!cbVer) { @@ -2427,7 +2427,7 @@ BOOL result = FALSE; if (VerQueryValueW(pData, L"\\", (LPVOID*)&ffi, &cb) && - ffi->dwFileVersionMS == 0x000A0000 && ffi->dwFileVersionLS >= 0x26C40000) { + ffi->dwFileVersionMS == 0x000A0000 && ffi->dwFileVersionLS >= 0x27990000) { result = TRUE; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 8 05:48:13 2015 From: python-checkins at python.org (steve.dower) Date: Wed, 08 Jul 2015 03:48:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Closes_24584=3A_Windows_installer_incorrectly_detects_CR?= =?utf-8?q?T_version_on_Windows_10?= Message-ID: <20150708034810.23227.5004@psf.io> https://hg.python.org/cpython/rev/877f47ca3b79 changeset: 96880:877f47ca3b79 parent: 96878:648c9fb3bdf5 parent: 96879:60eb61d6fdb4 user: Steve Dower date: Tue Jul 07 20:47:49 2015 -0700 summary: Closes 24584: Windows installer incorrectly detects CRT version on Windows 10 files: Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp --- a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp +++ b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp @@ -2399,10 +2399,10 @@ return FALSE; } - // Check whether at least CRT v10.0.9924.0 is available. + // Check whether at least CRT v10.0.10137.0 is available. // It should only be installed as a Windows Update package, which means // we don't need to worry about 32-bit/64-bit. - LPCWSTR crtFile = L"api-ms-win-crt-runtime-l1-1-0.dll"; + LPCWSTR crtFile = L"ucrtbase.dll"; DWORD cbVer = GetFileVersionInfoSizeW(crtFile, nullptr); if (!cbVer) { @@ -2427,7 +2427,7 @@ BOOL result = FALSE; if (VerQueryValueW(pData, L"\\", (LPVOID*)&ffi, &cb) && - ffi->dwFileVersionMS == 0x000A0000 && ffi->dwFileVersionLS >= 0x26C40000) { + ffi->dwFileVersionMS == 0x000A0000 && ffi->dwFileVersionLS >= 0x27990000) { result = TRUE; } -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Wed Jul 8 10:45:11 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 08 Jul 2015 08:45:11 +0000 Subject: [Python-checkins] Daily reference leaks (877f47ca3b79): sum=5 Message-ID: <20150708084503.12463.96779@psf.io> results for 877f47ca3b79 on branch "default" -------------------------------------------- test_functools leaked [0, 2, 2] memory blocks, sum=4 test_smtplib leaked [0, 0, 1] references, sum=1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogxS5T53', '--timeout', '7200'] From python-checkins at python.org Wed Jul 8 20:52:44 2015 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 08 Jul 2015 18:52:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Neaten-up_a_little_bit=2E?= Message-ID: <20150708185231.110676.57293@psf.io> https://hg.python.org/cpython/rev/d95cdd5b4ffb changeset: 96881:d95cdd5b4ffb user: Raymond Hettinger date: Wed Jul 08 11:52:27 2015 -0700 summary: Neaten-up a little bit. files: Objects/setobject.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -902,7 +902,7 @@ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)setiter_traverse, /* tp_traverse */ 0, /* tp_clear */ @@ -2145,7 +2145,7 @@ copy_doc}, {"difference", (PyCFunction)set_difference_multi, METH_VARARGS, difference_doc}, - {"intersection",(PyCFunction)set_intersection_multi, METH_VARARGS, + {"intersection", (PyCFunction)set_intersection_multi, METH_VARARGS, intersection_doc}, {"isdisjoint", (PyCFunction)set_isdisjoint, METH_O, isdisjoint_doc}, @@ -2216,7 +2216,7 @@ (traverseproc)set_traverse, /* tp_traverse */ (inquiry)set_clear_internal, /* tp_clear */ (richcmpfunc)set_richcompare, /* tp_richcompare */ - offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */ + offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */ (getiterfunc)set_iter, /* tp_iter */ 0, /* tp_iternext */ frozenset_methods, /* tp_methods */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 8 22:03:35 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 08 Jul 2015 20:03:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Added_regression_test_for_issue24581=2E?= Message-ID: <20150708200335.3102.72096@psf.io> https://hg.python.org/cpython/rev/844bd42326fa changeset: 96884:844bd42326fa branch: 3.5 parent: 96879:60eb61d6fdb4 parent: 96882:8644744f53ce user: Serhiy Storchaka date: Wed Jul 08 23:02:18 2015 +0300 summary: Added regression test for issue24581. files: Lib/test/test_set.py | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -1731,6 +1731,17 @@ be_bad = True set1.symmetric_difference_update(dict2) + def test_iter_and_mutate(self): + # Issue #24581 + s = set(range(100)) + s.clear() + s.update(range(100)) + si = iter(s) + s.clear() + a = list(range(100)) + s.update(range(100)) + list(si) + # Application tests (based on David Eppstein's graph recipes ==================================== def powerset(U): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 8 22:03:35 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 08 Jul 2015 20:03:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E5_-=3E_default?= =?utf-8?q?=29=3A_Added_regression_test_for_issue24581=2E?= Message-ID: <20150708200335.6282.82563@psf.io> https://hg.python.org/cpython/rev/9d296d5b6941 changeset: 96885:9d296d5b6941 parent: 96881:d95cdd5b4ffb parent: 96884:844bd42326fa user: Serhiy Storchaka date: Wed Jul 08 23:02:51 2015 +0300 summary: Added regression test for issue24581. files: Lib/test/test_set.py | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -1731,6 +1731,17 @@ be_bad = True set1.symmetric_difference_update(dict2) + def test_iter_and_mutate(self): + # Issue #24581 + s = set(range(100)) + s.clear() + s.update(range(100)) + si = iter(s) + s.clear() + a = list(range(100)) + s.update(range(100)) + list(si) + # Application tests (based on David Eppstein's graph recipes ==================================== def powerset(U): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 8 22:03:36 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 08 Jul 2015 20:03:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Added_regressi?= =?utf-8?q?on_test_for_issue24581=2E?= Message-ID: <20150708200335.110093.12200@psf.io> https://hg.python.org/cpython/rev/cfb84be6c7fc changeset: 96883:cfb84be6c7fc branch: 2.7 parent: 96861:4796dec0a7d0 user: Serhiy Storchaka date: Wed Jul 08 22:58:55 2015 +0300 summary: Added regression test for issue24581. files: Lib/test/test_set.py | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -1648,6 +1648,17 @@ be_bad = True set1.symmetric_difference_update(dict2) + def test_iter_and_mutate(self): + # Issue #24581 + s = set(range(100)) + s.clear() + s.update(range(100)) + si = iter(s) + s.clear() + a = list(range(100)) + s.update(range(100)) + list(si) + # Application tests (based on David Eppstein's graph recipes ==================================== def powerset(U): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Jul 8 22:03:36 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 08 Jul 2015 20:03:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Added_regressi?= =?utf-8?q?on_test_for_issue24581=2E?= Message-ID: <20150708200334.7742.64975@psf.io> https://hg.python.org/cpython/rev/8644744f53ce changeset: 96882:8644744f53ce branch: 3.4 parent: 96870:ed6ec65f50d2 user: Serhiy Storchaka date: Wed Jul 08 22:58:55 2015 +0300 summary: Added regression test for issue24581. files: Lib/test/test_set.py | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -1731,6 +1731,17 @@ be_bad = True set1.symmetric_difference_update(dict2) + def test_iter_and_mutate(self): + # Issue #24581 + s = set(range(100)) + s.clear() + s.update(range(100)) + si = iter(s) + s.clear() + a = list(range(100)) + s.update(range(100)) + list(si) + # Application tests (based on David Eppstein's graph recipes ==================================== def powerset(U): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Jul 9 05:19:45 2015 From: python-checkins at python.org (steve.dower) Date: Thu, 09 Jul 2015 03:19:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NTg1?= =?utf-8?q?=3A_Enables_build-to-build_upgrades_that_preserve_settings=2E?= Message-ID: <20150709031945.10428.23510@psf.io> https://hg.python.org/cpython/rev/8e18d615988e changeset: 96886:8e18d615988e branch: 3.5 parent: 96884:844bd42326fa user: Steve Dower date: Wed Jul 08 20:18:44 2015 -0700 summary: Issue #24585: Enables build-to-build upgrades that preserve settings. Rather than using Burn "Persisted" variables we now add registry keys for each added feature. These can be detected by the installer regardless of which version installed them, and we use this for Modify and Upgrade. In particular, Upgrades can't access the Persisted variables, but can find well-known registry keys. There are also some changes to the bootstrap app to properly handle upgrades. Finally, a few minor improvements to the Windows build to keep things tidier. files: PCbuild/build.bat | 27 +- PCbuild/python.props | 39 +- Tools/msi/build.bat | 8 +- Tools/msi/bundle/Default.thm | 13 +- Tools/msi/bundle/Default.wxl | 14 +- Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp | 367 +++++++-- Tools/msi/bundle/bootstrap/pythonba.vcxproj | 2 +- Tools/msi/bundle/bundle.wxs | 40 +- Tools/msi/bundle/packagegroups/core.wxs | 6 + Tools/msi/bundle/packagegroups/dev.wxs | 4 + Tools/msi/bundle/packagegroups/doc.wxs | 2 + Tools/msi/bundle/packagegroups/exe.wxs | 6 + Tools/msi/bundle/packagegroups/lib.wxs | 6 + Tools/msi/bundle/packagegroups/postinstall.wxs | 4 + Tools/msi/bundle/packagegroups/tcltk.wxs | 6 + Tools/msi/bundle/packagegroups/test.wxs | 6 + Tools/msi/bundle/packagegroups/tools.wxs | 2 + Tools/msi/common.wxs | 9 + Tools/msi/core/core_d.wxs | 1 + Tools/msi/core/core_pdb.wxs | 1 + Tools/msi/dev/dev.wxs | 1 + Tools/msi/doc/doc.wxs | 5 +- Tools/msi/exe/exe.wxs | 2 + Tools/msi/exe/exe_files.wxs | 1 + Tools/msi/launcher/launcher_files.wxs | 5 +- Tools/msi/launcher/launcher_reg.wxs | 2 +- Tools/msi/lib/lib.wxs | 1 + Tools/msi/msi.props | 6 +- Tools/msi/path/path.wxs | 8 +- Tools/msi/pip/pip.wxs | 4 +- Tools/msi/tcltk/tcltk.wxs | 1 + Tools/msi/test/test.wxs | 1 + Tools/msi/tools/tools.wxs | 1 + 33 files changed, 461 insertions(+), 140 deletions(-) diff --git a/PCbuild/build.bat b/PCbuild/build.bat --- a/PCbuild/build.bat +++ b/PCbuild/build.bat @@ -25,16 +25,17 @@ set kill= :CheckOpts -if '%1'=='-c' (set conf=%2) & shift & shift & goto CheckOpts -if '%1'=='-p' (set platf=%2) & shift & shift & goto CheckOpts -if '%1'=='-r' (set target=Rebuild) & shift & goto CheckOpts -if '%1'=='-t' (set target=%2) & shift & shift & goto CheckOpts -if '%1'=='-d' (set conf=Debug) & shift & goto CheckOpts -if '%1'=='-e' call "%dir%get_externals.bat" & shift & goto CheckOpts -if '%1'=='-m' (set parallel=/m) & shift & goto CheckOpts -if '%1'=='-M' (set parallel=) & shift & goto CheckOpts -if '%1'=='-v' (set verbose=/v:n) & shift & goto CheckOpts -if '%1'=='-k' (set kill=true) & shift & goto CheckOpts +if '%~1'=='-c' (set conf=%2) & shift & shift & goto CheckOpts +if '%~1'=='-p' (set platf=%2) & shift & shift & goto CheckOpts +if '%~1'=='-r' (set target=Rebuild) & shift & goto CheckOpts +if '%~1'=='-t' (set target=%2) & shift & shift & goto CheckOpts +if '%~1'=='-d' (set conf=Debug) & shift & goto CheckOpts +if '%~1'=='-e' call "%dir%get_externals.bat" & shift & goto CheckOpts +if '%~1'=='-m' (set parallel=/m) & shift & goto CheckOpts +if '%~1'=='-M' (set parallel=) & shift & goto CheckOpts +if '%~1'=='-v' (set verbose=/v:n) & shift & goto CheckOpts +if '%~1'=='-k' (set kill=true) & shift & goto CheckOpts +if '%~1'=='-V' shift & goto Version if '%platf%'=='x64' (set vs_platf=x86_amd64) @@ -50,3 +51,9 @@ rem batch is, shall we say, "lackluster" echo on msbuild "%dir%pcbuild.proj" /t:%target% %parallel% %verbose% /p:Configuration=%conf% /p:Platform=%platf% %1 %2 %3 %4 %5 %6 %7 %8 %9 + + at goto :eof + +:Version +rem Display the current build version information +msbuild "%dir%python.props" /t:ShowVersionInfo /v:m /nologo %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -42,7 +42,9 @@ $(BuildPath)python$(PyDebugExt).exe - + + + + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[1].Value) + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[2].Value) + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[3].Value) + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[4].Value) + <_ReleaseLevel>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[5].Value) + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[6].Value) + 0 + 15 + 10 + 11 + 12 + + + $(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber) $(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)$(ReleaseLevelName) $([msbuild]::BitwiseOr( @@ -110,7 +145,7 @@ - + diff --git a/Tools/msi/build.bat b/Tools/msi/build.bat --- a/Tools/msi/build.bat +++ b/Tools/msi/build.bat @@ -8,10 +8,10 @@ set BUILDDOC= :CheckOpts -if "%1" EQU "-h" goto Help -if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts -if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts -if "%1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts +if "%~1" EQU "-h" goto Help +if "%~1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts +if "%~1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts +if "%~1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) diff --git a/Tools/msi/bundle/Default.thm b/Tools/msi/bundle/Default.thm --- a/Tools/msi/bundle/Default.thm +++ b/Tools/msi/bundle/Default.thm @@ -21,13 +21,24 @@ #(loc.InstallMessage) - + #(loc.ShortPrependPathLabel) + + #(loc.InstallUpgradeHeader) + + + #(loc.InstallUpgradeMessage) + + + + + + #(loc.InstallHeader) diff --git a/Tools/msi/bundle/Default.wxl b/Tools/msi/bundle/Default.wxl --- a/Tools/msi/bundle/Default.wxl +++ b/Tools/msi/bundle/Default.wxl @@ -21,6 +21,8 @@ Install [WixBundleName] Select Install Now to install Python with default settings, or choose Customize to enable or disable features. Version [WixBundleVersion] + Upgrade to [WixBundleName] + Select Upgrade Now to keep your current settings, or choose Customize to enable or disable features. Are you sure you want to cancel? Previous version Setup Help @@ -40,8 +42,8 @@ Logs to a specific file. By default, log files are created in %TEMP%. [WixBundleName] <a href="#">license terms</a>. I &agree to the license terms and conditions - &Install Now - [DefaultJustForMeTargetDir] + &Install Now + [DefaultJustForMeTargetDir] Includes IDLE, pip and documentation Creates shortcuts and file associations @@ -49,6 +51,13 @@ Choose location and features &Install Uses setting preselected by your administrator + &Upgrade Now + [TargetDir] + +Replaces your existing installation without changing settings. +Select Customize to review current options. + C&ustomize installation + Choose location and features Optional Features Advanced Options Customize install location @@ -107,4 +116,5 @@ One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>. You must restart your computer to complete the rollback of the software. &Restart + Unable to install [WixBundleName] due to an existing install. Use Programs and Features to modify, repair or remove [WixBundleName]. diff --git a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp --- a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp +++ b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp @@ -47,6 +47,7 @@ PAGE_LOADING, PAGE_HELP, PAGE_INSTALL, + PAGE_UPGRADE, PAGE_SIMPLE_INSTALL, PAGE_CUSTOM1, PAGE_CUSTOM2, @@ -63,6 +64,7 @@ L"Loading", L"Help", L"Install", + L"Upgrade", L"SimpleInstall", L"Custom1", L"Custom2", @@ -79,10 +81,11 @@ ID_MINIMIZE_BUTTON, // Welcome page - ID_INSTALL_ALL_USERS_BUTTON, - ID_INSTALL_JUST_FOR_ME_BUTTON, + ID_INSTALL_BUTTON, ID_INSTALL_CUSTOM_BUTTON, ID_INSTALL_SIMPLE_BUTTON, + ID_INSTALL_UPGRADE_BUTTON, + ID_INSTALL_UPGRADE_CUSTOM_BUTTON, ID_INSTALL_CANCEL_BUTTON, // Customize Page @@ -141,10 +144,11 @@ { ID_CLOSE_BUTTON, L"CloseButton" }, { ID_MINIMIZE_BUTTON, L"MinimizeButton" }, - { ID_INSTALL_ALL_USERS_BUTTON, L"InstallAllUsersButton" }, - { ID_INSTALL_JUST_FOR_ME_BUTTON, L"InstallJustForMeButton" }, + { ID_INSTALL_BUTTON, L"InstallButton" }, { ID_INSTALL_CUSTOM_BUTTON, L"InstallCustomButton" }, { ID_INSTALL_SIMPLE_BUTTON, L"InstallSimpleButton" }, + { ID_INSTALL_UPGRADE_BUTTON, L"InstallUpgradeButton" }, + { ID_INSTALL_UPGRADE_CUSTOM_BUTTON, L"InstallUpgradeCustomButton" }, { ID_INSTALL_CANCEL_BUTTON, L"InstallCancelButton" }, { ID_TARGETDIR_EDITBOX, L"TargetDir" }, @@ -191,13 +195,35 @@ { ID_FAILURE_CANCEL_BUTTON, L"FailureCancelButton" }, }; +static struct { LPCWSTR regName; LPCWSTR variableName; } OPTIONAL_FEATURES[] = { + { L"core_d", L"Include_debug" }, + { L"core_pdb", L"Include_symbols" }, + { L"dev", L"Include_dev" }, + { L"doc", L"Include_doc" }, + { L"exe", L"Include_exe" }, + { L"lib", L"Include_lib" }, + { L"path", L"PrependPath" }, + { L"pip", L"Include_pip" }, + { L"tcltk", L"Include_tcltk" }, + { L"test", L"Include_test" }, + { L"tools", L"Include_tools" }, + { L"Shortcuts", L"Shortcuts" }, + // Include_launcher and AssociateFiles are handled separately and so do + // not need to be included in this list. + { nullptr, nullptr } +}; + + + class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication { void ShowPage(DWORD newPageId) { // Process each control for special handling in the new page. ProcessPageControls(ThemeGetPage(_theme, newPageId)); // Enable disable controls per-page. - if (_pageIds[PAGE_INSTALL] == newPageId || _pageIds[PAGE_SIMPLE_INSTALL] == newPageId) { + if (_pageIds[PAGE_INSTALL] == newPageId || + _pageIds[PAGE_SIMPLE_INSTALL] == newPageId || + _pageIds[PAGE_UPGRADE] == newPageId) { InstallPage_Show(); } else if (_pageIds[PAGE_CUSTOM1] == newPageId) { Custom1Page_Show(); @@ -222,7 +248,7 @@ // On the install page set the focus to the install button or // the next enabled control if install is disabled if (_pageIds[PAGE_INSTALL] == newPageId) { - ThemeSetFocus(_theme, ID_INSTALL_ALL_USERS_BUTTON); + ThemeSetFocus(_theme, ID_INSTALL_BUTTON); } else if (_pageIds[PAGE_SIMPLE_INSTALL] == newPageId) { ThemeSetFocus(_theme, ID_INSTALL_SIMPLE_BUTTON); } @@ -234,7 +260,7 @@ void OnCommand(CONTROL_ID id) { LPWSTR defaultDir = nullptr; LPWSTR targetDir = nullptr; - LONGLONG elevated, crtInstalled; + LONGLONG elevated, crtInstalled, installAllUsers; BOOL checked; WCHAR wzPath[MAX_PATH] = { }; BROWSEINFOW browseInfo = { }; @@ -247,87 +273,42 @@ break; // Install commands - case ID_INSTALL_SIMPLE_BUTTON: - hr = BalGetStringVariable(L"TargetDir", &targetDir); - if (FAILED(hr) || !targetDir || !*targetDir) { - LONGLONG installAll; - if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll) { - hr = BalGetStringVariable(L"DefaultAllUsersTargetDir", &defaultDir); - BalExitOnFailure(hr, "Failed to get the default all users install directory"); - } else { - hr = BalGetStringVariable(L"DefaultJustForMeTargetDir", &defaultDir); - BalExitOnFailure(hr, "Failed to get the default per-user install directory"); - } - - if (!defaultDir || !*defaultDir) { - BalLogError(E_INVALIDARG, "Default install directory is blank"); - } - - hr = BalFormatString(defaultDir, &targetDir); - BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); - - hr = _engine->SetVariableString(L"TargetDir", targetDir); - ReleaseStr(targetDir); - BalExitOnFailure(hr, "Failed to set install target directory"); - } else { - ReleaseStr(targetDir); - } - - OnPlan(BOOTSTRAPPER_ACTION_INSTALL); - break; - - case ID_INSTALL_ALL_USERS_BUTTON: - SavePageSettings(); - - hr = _engine->SetVariableNumeric(L"InstallAllUsers", 1); - ExitOnFailure(hr, L"Failed to set install scope"); - - hr = _engine->SetVariableNumeric(L"CompileAll", 1); - ExitOnFailure(hr, L"Failed to set compile all setting"); - - hr = BalGetStringVariable(L"DefaultAllUsersTargetDir", &defaultDir); - BalExitOnFailure(hr, "Failed to get the default all users install directory"); - - if (!defaultDir || !*defaultDir) { - BalLogError(E_INVALIDARG, "Default install directory is blank"); - } - - hr = BalFormatString(defaultDir, &targetDir); - BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); - - hr = _engine->SetVariableString(L"TargetDir", targetDir); - ReleaseStr(targetDir); - BalExitOnFailure(hr, "Failed to set install target directory"); - - OnPlan(BOOTSTRAPPER_ACTION_INSTALL); - break; - - case ID_INSTALL_JUST_FOR_ME_BUTTON: + case ID_INSTALL_SIMPLE_BUTTON: __fallthrough; + case ID_INSTALL_UPGRADE_BUTTON: __fallthrough; + case ID_INSTALL_BUTTON: SavePageSettings(); if (!QueryElevateForCrtInstall()) { break; } - hr = _engine->SetVariableNumeric(L"InstallAllUsers", 0); - ExitOnFailure(hr, L"Failed to set install scope"); - - hr = _engine->SetVariableNumeric(L"CompileAll", 0); - ExitOnFailure(hr, L"Failed to unset CompileAll"); - - hr = BalGetStringVariable(L"DefaultJustForMeTargetDir", &defaultDir); - BalExitOnFailure(hr, "Failed to get the default per-user install directory"); - - if (!defaultDir || !*defaultDir) { - BalLogError(E_INVALIDARG, "Default install directory is blank"); + hr = BalGetNumericVariable(L"InstallAllUsers", &installAllUsers); + ExitOnFailure(hr, L"Failed to get install scope"); + + hr = _engine->SetVariableNumeric(L"CompileAll", installAllUsers); + ExitOnFailure(hr, L"Failed to update CompileAll"); + + hr = BalGetStringVariable(L"TargetDir", &targetDir); + if (FAILED(hr) || !targetDir || !targetDir[0]) { + ReleaseStr(targetDir); + + hr = BalGetStringVariable( + installAllUsers ? L"DefaultAllUsersTargetDir" : L"DefaultJustForMeTargetDir", + &defaultDir + ); + BalExitOnFailure(hr, "Failed to get the default install directory"); + + if (!defaultDir || !defaultDir[0]) { + BalLogError(E_INVALIDARG, "Default install directory is blank"); + } + + hr = BalFormatString(defaultDir, &targetDir); + BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); + + hr = _engine->SetVariableString(L"TargetDir", targetDir); + BalExitOnFailure(hr, "Failed to set install target directory"); } - - hr = BalFormatString(defaultDir, &targetDir); - BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); - - hr = _engine->SetVariableString(L"TargetDir", targetDir); ReleaseStr(targetDir); - BalExitOnFailure(hr, "Failed to set install target directory"); OnPlan(BOOTSTRAPPER_ACTION_INSTALL); break; @@ -342,6 +323,7 @@ break; case ID_INSTALL_CUSTOM_BUTTON: __fallthrough; + case ID_INSTALL_UPGRADE_CUSTOM_BUTTON: __fallthrough; case ID_CUSTOM2_BACK_BUTTON: SavePageSettings(); GoToPage(PAGE_CUSTOM1); @@ -460,10 +442,11 @@ elevated = 0; } - ThemeControlElevates(_theme, ID_INSTALL_ALL_USERS_BUTTON, !elevated); - - if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll) { - ThemeControlElevates(_theme, ID_INSTALL_SIMPLE_BUTTON, !elevated); + + if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll && !elevated) { + ThemeControlElevates(_theme, ID_INSTALL_BUTTON, TRUE); + ThemeControlElevates(_theme, ID_INSTALL_SIMPLE_BUTTON, TRUE); + ThemeControlElevates(_theme, ID_INSTALL_UPGRADE_BUTTON, TRUE); } } @@ -667,7 +650,34 @@ // Remember when our bundle would cause a downgrade. if (BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE == operation) { - _downgrading = TRUE; + _downgradingOtherVersion = TRUE; + } else if (BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE == operation) { + _upgradingOldVersion = TRUE; + + // Assume we don't want the launcher or file associations, and if + // they have already been installed then loading the state will + // reactivate these settings. + _engine->SetVariableNumeric(L"Include_launcher", 0); + _engine->SetVariableNumeric(L"AssociateFiles", 0); + auto hr = LoadLauncherStateFromKey(_engine, HKEY_CURRENT_USER); + if (hr == S_FALSE) { + hr = LoadLauncherStateFromKey(_engine, HKEY_LOCAL_MACHINE); + } + } else if (BOOTSTRAPPER_RELATED_OPERATION_NONE == operation) { + if (_command.action == BOOTSTRAPPER_ACTION_INSTALL) { + LOC_STRING *pLocString = nullptr; + if (SUCCEEDED(LocGetString(_wixLoc, L"#(loc.FailureExistingInstall)", &pLocString)) && pLocString) { + BalFormatString(pLocString->wzText, &_failedMessage); + } else { + BalFormatString(L"Cannot install [WixBundleName] because it is already installed.", &_failedMessage); + } + BalLog( + BOOTSTRAPPER_LOG_LEVEL_ERROR, + "Related bundle %ls is preventing install", + wzBundleId + ); + SetState(PYBA_STATE_FAILED, E_WIXSTDBA_CONDITION_FAILED); + } } return CheckCanceled() ? IDCANCEL : IDOK; @@ -1969,7 +1979,7 @@ BalExitOnFailure(hr, "Failed to update strings"); // If we are going to apply a downgrade, bail. - if (_downgrading && BOOTSTRAPPER_ACTION_UNINSTALL < action) { + if (_downgradingOtherVersion && BOOTSTRAPPER_ACTION_UNINSTALL < action) { if (_suppressDowngradeFailure) { BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "A newer version of this product is installed but downgrade failure has been suppressed; continuing..."); } else { @@ -2354,7 +2364,9 @@ if (_installPage == PAGE_LOADING) { switch (_command.action) { case BOOTSTRAPPER_ACTION_INSTALL: - if (SUCCEEDED(BalGetNumericVariable(L"SimpleInstall", &simple)) && simple) { + if (_upgradingOldVersion) { + _installPage = PAGE_UPGRADE; + } else if (SUCCEEDED(BalGetNumericVariable(L"SimpleInstall", &simple)) && simple) { _installPage = PAGE_SIMPLE_INSTALL; } else { _installPage = PAGE_INSTALL; @@ -2608,6 +2620,179 @@ } } + static bool IsTargetPlatformx64(__in IBootstrapperEngine* pEngine) { + WCHAR platform[8]; + DWORD platformLen = 8; + + if (FAILED(pEngine->GetVariableString(L"TargetPlatform", platform, &platformLen))) { + return S_FALSE; + } + + return ::CompareStringW(LOCALE_NEUTRAL, 0, platform, -1, L"x64", -1) == CSTR_EQUAL; + } + + static HRESULT LoadOptionalFeatureStatesFromKey( + __in IBootstrapperEngine* pEngine, + __in HKEY hkHive, + __in LPCWSTR subkey + ) { + HKEY hKey; + LRESULT res; + + if (IsTargetPlatformx64(pEngine)) { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + } else { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); + } + if (res == ERROR_FILE_NOT_FOUND) { + return S_FALSE; + } + if (res != ERROR_SUCCESS) { + return HRESULT_FROM_WIN32(res); + } + + for (auto p = OPTIONAL_FEATURES; p->regName; ++p) { + res = RegQueryValueExW(hKey, p->regName, nullptr, nullptr, nullptr, nullptr); + if (res == ERROR_FILE_NOT_FOUND) { + pEngine->SetVariableNumeric(p->variableName, 0); + } else if (res == ERROR_SUCCESS) { + pEngine->SetVariableNumeric(p->variableName, 1); + } else { + RegCloseKey(hKey); + return HRESULT_FROM_WIN32(res); + } + } + + RegCloseKey(hKey); + return S_OK; + } + + static HRESULT LoadTargetDirFromKey( + __in IBootstrapperEngine* pEngine, + __in HKEY hkHive, + __in LPCWSTR subkey + ) { + HKEY hKey; + LRESULT res; + DWORD dataType; + BYTE buffer[1024]; + DWORD bufferLen = sizeof(buffer); + + if (IsTargetPlatformx64(pEngine)) { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + } else { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); + } + if (res == ERROR_FILE_NOT_FOUND) { + return S_FALSE; + } + if (res != ERROR_SUCCESS) { + return HRESULT_FROM_WIN32(res); + } + + res = RegQueryValueExW(hKey, nullptr, nullptr, &dataType, buffer, &bufferLen); + if (res == ERROR_SUCCESS && dataType == REG_SZ && bufferLen < sizeof(buffer)) { + pEngine->SetVariableString(L"TargetDir", reinterpret_cast(buffer)); + } + RegCloseKey(hKey); + return HRESULT_FROM_WIN32(res); + } + + static HRESULT LoadLauncherStateFromKey( + __in IBootstrapperEngine* pEngine, + __in HKEY hkHive + ) { + const LPCWSTR subkey = L"Software\\Python\\PyLauncher"; + HKEY hKey; + LRESULT res; + + if (IsTargetPlatformx64(pEngine)) { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + } else { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); + } + + if (res == ERROR_FILE_NOT_FOUND) { + return S_FALSE; + } + if (res != ERROR_SUCCESS) { + return HRESULT_FROM_WIN32(res); + } + + res = RegQueryValueExW(hKey, nullptr, nullptr, nullptr, nullptr, nullptr); + if (res == ERROR_FILE_NOT_FOUND) { + pEngine->SetVariableNumeric(L"Include_launcher", 0); + } else if (res == ERROR_SUCCESS) { + pEngine->SetVariableNumeric(L"Include_launcher", 1); + } + + res = RegQueryValueExW(hKey, L"AssociateFiles", nullptr, nullptr, nullptr, nullptr); + if (res == ERROR_FILE_NOT_FOUND) { + pEngine->SetVariableNumeric(L"AssociateFiles", 0); + } else if (res == ERROR_SUCCESS) { + pEngine->SetVariableNumeric(L"AssociateFiles", 1); + } + + RegCloseKey(hKey); + return S_OK; + } + + static void LoadOptionalFeatureStates(__in IBootstrapperEngine* pEngine) { + WCHAR subkeyFmt[256]; + WCHAR subkey[256]; + DWORD subkeyLen; + HRESULT hr; + HKEY hkHive; + + // The launcher installation is separate from the Python install, so we + // check its state later. This also checks the file association option. + + // Get the registry key from the bundle, to save having to duplicate it + // in multiple places. + subkeyLen = sizeof(subkeyFmt) / sizeof(subkeyFmt[0]); + hr = pEngine->GetVariableString(L"OptionalFeaturesRegistryKey", subkeyFmt, &subkeyLen); + BalExitOnFailure(hr, "Failed to locate registry key"); + subkeyLen = sizeof(subkey) / sizeof(subkey[0]); + hr = pEngine->FormatString(subkeyFmt, subkey, &subkeyLen); + BalExitOnFailure1(hr, "Failed to format %ls", subkeyFmt); + + // Check the current user's registry for existing features + hkHive = HKEY_CURRENT_USER; + hr = LoadOptionalFeatureStatesFromKey(pEngine, hkHive, subkey); + BalExitOnFailure1(hr, "Failed to read from HKCU\\%ls", subkey); + if (hr == S_FALSE) { + // Now check the local machine registry + hkHive = HKEY_LOCAL_MACHINE; + hr = LoadOptionalFeatureStatesFromKey(pEngine, hkHive, subkey); + BalExitOnFailure1(hr, "Failed to read from HKLM\\%ls", subkey); + if (hr == S_OK) { + // Found a system-wide install, so enable these settings. + pEngine->SetVariableNumeric(L"InstallAllUsers", 1); + pEngine->SetVariableNumeric(L"CompileAll", 1); + } + } + + if (hr == S_OK) { + // Cannot change InstallAllUsersState when upgrading. While there's + // no good reason to not allow installing a per-user and an all-user + // version simultaneously, Burn can't handle the state management + // and will need to uninstall the old one. + pEngine->SetVariableString(L"InstallAllUsersState", L"disable"); + + // Get the previous install directory. This can be changed by the + // user. + subkeyLen = sizeof(subkeyFmt) / sizeof(subkeyFmt[0]); + hr = pEngine->GetVariableString(L"TargetDirRegistryKey", subkeyFmt, &subkeyLen); + BalExitOnFailure(hr, "Failed to locate registry key"); + subkeyLen = sizeof(subkey) / sizeof(subkey[0]); + hr = pEngine->FormatString(subkeyFmt, subkey, &subkeyLen); + BalExitOnFailure1(hr, "Failed to format %ls", subkeyFmt); + LoadTargetDirFromKey(pEngine, hkHive, subkey); + } + + LExit: + return; + } public: // @@ -2667,7 +2852,8 @@ _installPage = PAGE_LOADING; _hrFinal = hrHostInitialization; - _downgrading = FALSE; + _downgradingOtherVersion = FALSE; + _upgradingOldVersion = FALSE; _restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE; _restartRequired = FALSE; _allowRestart = FALSE; @@ -2690,6 +2876,8 @@ _hBAFModule = nullptr; _baFunction = nullptr; + + LoadOptionalFeatureStates(pEngine); } @@ -2748,7 +2936,8 @@ DWORD _calculatedCacheProgress; DWORD _calculatedExecuteProgress; - BOOL _downgrading; + BOOL _downgradingOtherVersion; + BOOL _upgradingOldVersion; BOOTSTRAPPER_APPLY_RESTART _restartResult; BOOL _restartRequired; BOOL _allowRestart; diff --git a/Tools/msi/bundle/bootstrap/pythonba.vcxproj b/Tools/msi/bundle/bootstrap/pythonba.vcxproj --- a/Tools/msi/bundle/bootstrap/pythonba.vcxproj +++ b/Tools/msi/bundle/bootstrap/pythonba.vcxproj @@ -31,7 +31,7 @@ DynamicLibrary Unicode - $(ProjectDir)..\..\obj\$(Configuration)_Bootstrap\ + $(PySourcePath)PCBuild\obj\$(Configuration)_$(Platform)_Setup\Bootstrap\ $(IntDir) diff --git a/Tools/msi/bundle/bundle.wxs b/Tools/msi/bundle/bundle.wxs --- a/Tools/msi/bundle/bundle.wxs +++ b/Tools/msi/bundle/bundle.wxs @@ -23,14 +23,18 @@ - - + + + + + + $(BuildPath)python$(PyDebugExt).exe - + + + + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[1].Value) + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[2].Value) + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[3].Value) + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[4].Value) + <_ReleaseLevel>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[5].Value) + $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[6].Value) + 0 + 15 + 10 + 11 + 12 + + + $(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber) $(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)$(ReleaseLevelName) $([msbuild]::BitwiseOr( @@ -110,7 +145,7 @@ - + diff --git a/Tools/msi/build.bat b/Tools/msi/build.bat --- a/Tools/msi/build.bat +++ b/Tools/msi/build.bat @@ -8,10 +8,10 @@ set BUILDDOC= :CheckOpts -if "%1" EQU "-h" goto Help -if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts -if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts -if "%1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts +if "%~1" EQU "-h" goto Help +if "%~1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts +if "%~1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts +if "%~1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) diff --git a/Tools/msi/bundle/Default.thm b/Tools/msi/bundle/Default.thm --- a/Tools/msi/bundle/Default.thm +++ b/Tools/msi/bundle/Default.thm @@ -21,13 +21,24 @@ #(loc.InstallMessage) - + #(loc.ShortPrependPathLabel) + + #(loc.InstallUpgradeHeader) + + + #(loc.InstallUpgradeMessage) + + + + + + #(loc.InstallHeader) diff --git a/Tools/msi/bundle/Default.wxl b/Tools/msi/bundle/Default.wxl --- a/Tools/msi/bundle/Default.wxl +++ b/Tools/msi/bundle/Default.wxl @@ -21,6 +21,8 @@ Install [WixBundleName] Select Install Now to install Python with default settings, or choose Customize to enable or disable features. Version [WixBundleVersion] + Upgrade to [WixBundleName] + Select Upgrade Now to keep your current settings, or choose Customize to enable or disable features. Are you sure you want to cancel? Previous version Setup Help @@ -40,8 +42,8 @@ Logs to a specific file. By default, log files are created in %TEMP%. [WixBundleName] <a href="#">license terms</a>. I &agree to the license terms and conditions - &Install Now - [DefaultJustForMeTargetDir] + &Install Now + [DefaultJustForMeTargetDir] Includes IDLE, pip and documentation Creates shortcuts and file associations @@ -49,6 +51,13 @@ Choose location and features &Install Uses setting preselected by your administrator + &Upgrade Now + [TargetDir] + +Replaces your existing installation without changing settings. +Select Customize to review current options. + C&ustomize installation + Choose location and features Optional Features Advanced Options Customize install location @@ -107,4 +116,5 @@ One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>. You must restart your computer to complete the rollback of the software. &Restart + Unable to install [WixBundleName] due to an existing install. Use Programs and Features to modify, repair or remove [WixBundleName]. diff --git a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp --- a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp +++ b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp @@ -47,6 +47,7 @@ PAGE_LOADING, PAGE_HELP, PAGE_INSTALL, + PAGE_UPGRADE, PAGE_SIMPLE_INSTALL, PAGE_CUSTOM1, PAGE_CUSTOM2, @@ -63,6 +64,7 @@ L"Loading", L"Help", L"Install", + L"Upgrade", L"SimpleInstall", L"Custom1", L"Custom2", @@ -79,10 +81,11 @@ ID_MINIMIZE_BUTTON, // Welcome page - ID_INSTALL_ALL_USERS_BUTTON, - ID_INSTALL_JUST_FOR_ME_BUTTON, + ID_INSTALL_BUTTON, ID_INSTALL_CUSTOM_BUTTON, ID_INSTALL_SIMPLE_BUTTON, + ID_INSTALL_UPGRADE_BUTTON, + ID_INSTALL_UPGRADE_CUSTOM_BUTTON, ID_INSTALL_CANCEL_BUTTON, // Customize Page @@ -141,10 +144,11 @@ { ID_CLOSE_BUTTON, L"CloseButton" }, { ID_MINIMIZE_BUTTON, L"MinimizeButton" }, - { ID_INSTALL_ALL_USERS_BUTTON, L"InstallAllUsersButton" }, - { ID_INSTALL_JUST_FOR_ME_BUTTON, L"InstallJustForMeButton" }, + { ID_INSTALL_BUTTON, L"InstallButton" }, { ID_INSTALL_CUSTOM_BUTTON, L"InstallCustomButton" }, { ID_INSTALL_SIMPLE_BUTTON, L"InstallSimpleButton" }, + { ID_INSTALL_UPGRADE_BUTTON, L"InstallUpgradeButton" }, + { ID_INSTALL_UPGRADE_CUSTOM_BUTTON, L"InstallUpgradeCustomButton" }, { ID_INSTALL_CANCEL_BUTTON, L"InstallCancelButton" }, { ID_TARGETDIR_EDITBOX, L"TargetDir" }, @@ -191,13 +195,35 @@ { ID_FAILURE_CANCEL_BUTTON, L"FailureCancelButton" }, }; +static struct { LPCWSTR regName; LPCWSTR variableName; } OPTIONAL_FEATURES[] = { + { L"core_d", L"Include_debug" }, + { L"core_pdb", L"Include_symbols" }, + { L"dev", L"Include_dev" }, + { L"doc", L"Include_doc" }, + { L"exe", L"Include_exe" }, + { L"lib", L"Include_lib" }, + { L"path", L"PrependPath" }, + { L"pip", L"Include_pip" }, + { L"tcltk", L"Include_tcltk" }, + { L"test", L"Include_test" }, + { L"tools", L"Include_tools" }, + { L"Shortcuts", L"Shortcuts" }, + // Include_launcher and AssociateFiles are handled separately and so do + // not need to be included in this list. + { nullptr, nullptr } +}; + + + class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication { void ShowPage(DWORD newPageId) { // Process each control for special handling in the new page. ProcessPageControls(ThemeGetPage(_theme, newPageId)); // Enable disable controls per-page. - if (_pageIds[PAGE_INSTALL] == newPageId || _pageIds[PAGE_SIMPLE_INSTALL] == newPageId) { + if (_pageIds[PAGE_INSTALL] == newPageId || + _pageIds[PAGE_SIMPLE_INSTALL] == newPageId || + _pageIds[PAGE_UPGRADE] == newPageId) { InstallPage_Show(); } else if (_pageIds[PAGE_CUSTOM1] == newPageId) { Custom1Page_Show(); @@ -222,7 +248,7 @@ // On the install page set the focus to the install button or // the next enabled control if install is disabled if (_pageIds[PAGE_INSTALL] == newPageId) { - ThemeSetFocus(_theme, ID_INSTALL_ALL_USERS_BUTTON); + ThemeSetFocus(_theme, ID_INSTALL_BUTTON); } else if (_pageIds[PAGE_SIMPLE_INSTALL] == newPageId) { ThemeSetFocus(_theme, ID_INSTALL_SIMPLE_BUTTON); } @@ -234,7 +260,7 @@ void OnCommand(CONTROL_ID id) { LPWSTR defaultDir = nullptr; LPWSTR targetDir = nullptr; - LONGLONG elevated, crtInstalled; + LONGLONG elevated, crtInstalled, installAllUsers; BOOL checked; WCHAR wzPath[MAX_PATH] = { }; BROWSEINFOW browseInfo = { }; @@ -247,87 +273,42 @@ break; // Install commands - case ID_INSTALL_SIMPLE_BUTTON: - hr = BalGetStringVariable(L"TargetDir", &targetDir); - if (FAILED(hr) || !targetDir || !*targetDir) { - LONGLONG installAll; - if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll) { - hr = BalGetStringVariable(L"DefaultAllUsersTargetDir", &defaultDir); - BalExitOnFailure(hr, "Failed to get the default all users install directory"); - } else { - hr = BalGetStringVariable(L"DefaultJustForMeTargetDir", &defaultDir); - BalExitOnFailure(hr, "Failed to get the default per-user install directory"); - } - - if (!defaultDir || !*defaultDir) { - BalLogError(E_INVALIDARG, "Default install directory is blank"); - } - - hr = BalFormatString(defaultDir, &targetDir); - BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); - - hr = _engine->SetVariableString(L"TargetDir", targetDir); - ReleaseStr(targetDir); - BalExitOnFailure(hr, "Failed to set install target directory"); - } else { - ReleaseStr(targetDir); - } - - OnPlan(BOOTSTRAPPER_ACTION_INSTALL); - break; - - case ID_INSTALL_ALL_USERS_BUTTON: - SavePageSettings(); - - hr = _engine->SetVariableNumeric(L"InstallAllUsers", 1); - ExitOnFailure(hr, L"Failed to set install scope"); - - hr = _engine->SetVariableNumeric(L"CompileAll", 1); - ExitOnFailure(hr, L"Failed to set compile all setting"); - - hr = BalGetStringVariable(L"DefaultAllUsersTargetDir", &defaultDir); - BalExitOnFailure(hr, "Failed to get the default all users install directory"); - - if (!defaultDir || !*defaultDir) { - BalLogError(E_INVALIDARG, "Default install directory is blank"); - } - - hr = BalFormatString(defaultDir, &targetDir); - BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); - - hr = _engine->SetVariableString(L"TargetDir", targetDir); - ReleaseStr(targetDir); - BalExitOnFailure(hr, "Failed to set install target directory"); - - OnPlan(BOOTSTRAPPER_ACTION_INSTALL); - break; - - case ID_INSTALL_JUST_FOR_ME_BUTTON: + case ID_INSTALL_SIMPLE_BUTTON: __fallthrough; + case ID_INSTALL_UPGRADE_BUTTON: __fallthrough; + case ID_INSTALL_BUTTON: SavePageSettings(); if (!QueryElevateForCrtInstall()) { break; } - hr = _engine->SetVariableNumeric(L"InstallAllUsers", 0); - ExitOnFailure(hr, L"Failed to set install scope"); - - hr = _engine->SetVariableNumeric(L"CompileAll", 0); - ExitOnFailure(hr, L"Failed to unset CompileAll"); - - hr = BalGetStringVariable(L"DefaultJustForMeTargetDir", &defaultDir); - BalExitOnFailure(hr, "Failed to get the default per-user install directory"); - - if (!defaultDir || !*defaultDir) { - BalLogError(E_INVALIDARG, "Default install directory is blank"); + hr = BalGetNumericVariable(L"InstallAllUsers", &installAllUsers); + ExitOnFailure(hr, L"Failed to get install scope"); + + hr = _engine->SetVariableNumeric(L"CompileAll", installAllUsers); + ExitOnFailure(hr, L"Failed to update CompileAll"); + + hr = BalGetStringVariable(L"TargetDir", &targetDir); + if (FAILED(hr) || !targetDir || !targetDir[0]) { + ReleaseStr(targetDir); + + hr = BalGetStringVariable( + installAllUsers ? L"DefaultAllUsersTargetDir" : L"DefaultJustForMeTargetDir", + &defaultDir + ); + BalExitOnFailure(hr, "Failed to get the default install directory"); + + if (!defaultDir || !defaultDir[0]) { + BalLogError(E_INVALIDARG, "Default install directory is blank"); + } + + hr = BalFormatString(defaultDir, &targetDir); + BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); + + hr = _engine->SetVariableString(L"TargetDir", targetDir); + BalExitOnFailure(hr, "Failed to set install target directory"); } - - hr = BalFormatString(defaultDir, &targetDir); - BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); - - hr = _engine->SetVariableString(L"TargetDir", targetDir); ReleaseStr(targetDir); - BalExitOnFailure(hr, "Failed to set install target directory"); OnPlan(BOOTSTRAPPER_ACTION_INSTALL); break; @@ -342,6 +323,7 @@ break; case ID_INSTALL_CUSTOM_BUTTON: __fallthrough; + case ID_INSTALL_UPGRADE_CUSTOM_BUTTON: __fallthrough; case ID_CUSTOM2_BACK_BUTTON: SavePageSettings(); GoToPage(PAGE_CUSTOM1); @@ -460,10 +442,11 @@ elevated = 0; } - ThemeControlElevates(_theme, ID_INSTALL_ALL_USERS_BUTTON, !elevated); - - if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll) { - ThemeControlElevates(_theme, ID_INSTALL_SIMPLE_BUTTON, !elevated); + + if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll && !elevated) { + ThemeControlElevates(_theme, ID_INSTALL_BUTTON, TRUE); + ThemeControlElevates(_theme, ID_INSTALL_SIMPLE_BUTTON, TRUE); + ThemeControlElevates(_theme, ID_INSTALL_UPGRADE_BUTTON, TRUE); } } @@ -667,7 +650,34 @@ // Remember when our bundle would cause a downgrade. if (BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE == operation) { - _downgrading = TRUE; + _downgradingOtherVersion = TRUE; + } else if (BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE == operation) { + _upgradingOldVersion = TRUE; + + // Assume we don't want the launcher or file associations, and if + // they have already been installed then loading the state will + // reactivate these settings. + _engine->SetVariableNumeric(L"Include_launcher", 0); + _engine->SetVariableNumeric(L"AssociateFiles", 0); + auto hr = LoadLauncherStateFromKey(_engine, HKEY_CURRENT_USER); + if (hr == S_FALSE) { + hr = LoadLauncherStateFromKey(_engine, HKEY_LOCAL_MACHINE); + } + } else if (BOOTSTRAPPER_RELATED_OPERATION_NONE == operation) { + if (_command.action == BOOTSTRAPPER_ACTION_INSTALL) { + LOC_STRING *pLocString = nullptr; + if (SUCCEEDED(LocGetString(_wixLoc, L"#(loc.FailureExistingInstall)", &pLocString)) && pLocString) { + BalFormatString(pLocString->wzText, &_failedMessage); + } else { + BalFormatString(L"Cannot install [WixBundleName] because it is already installed.", &_failedMessage); + } + BalLog( + BOOTSTRAPPER_LOG_LEVEL_ERROR, + "Related bundle %ls is preventing install", + wzBundleId + ); + SetState(PYBA_STATE_FAILED, E_WIXSTDBA_CONDITION_FAILED); + } } return CheckCanceled() ? IDCANCEL : IDOK; @@ -1969,7 +1979,7 @@ BalExitOnFailure(hr, "Failed to update strings"); // If we are going to apply a downgrade, bail. - if (_downgrading && BOOTSTRAPPER_ACTION_UNINSTALL < action) { + if (_downgradingOtherVersion && BOOTSTRAPPER_ACTION_UNINSTALL < action) { if (_suppressDowngradeFailure) { BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "A newer version of this product is installed but downgrade failure has been suppressed; continuing..."); } else { @@ -2354,7 +2364,9 @@ if (_installPage == PAGE_LOADING) { switch (_command.action) { case BOOTSTRAPPER_ACTION_INSTALL: - if (SUCCEEDED(BalGetNumericVariable(L"SimpleInstall", &simple)) && simple) { + if (_upgradingOldVersion) { + _installPage = PAGE_UPGRADE; + } else if (SUCCEEDED(BalGetNumericVariable(L"SimpleInstall", &simple)) && simple) { _installPage = PAGE_SIMPLE_INSTALL; } else { _installPage = PAGE_INSTALL; @@ -2608,6 +2620,179 @@ } } + static bool IsTargetPlatformx64(__in IBootstrapperEngine* pEngine) { + WCHAR platform[8]; + DWORD platformLen = 8; + + if (FAILED(pEngine->GetVariableString(L"TargetPlatform", platform, &platformLen))) { + return S_FALSE; + } + + return ::CompareStringW(LOCALE_NEUTRAL, 0, platform, -1, L"x64", -1) == CSTR_EQUAL; + } + + static HRESULT LoadOptionalFeatureStatesFromKey( + __in IBootstrapperEngine* pEngine, + __in HKEY hkHive, + __in LPCWSTR subkey + ) { + HKEY hKey; + LRESULT res; + + if (IsTargetPlatformx64(pEngine)) { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + } else { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); + } + if (res == ERROR_FILE_NOT_FOUND) { + return S_FALSE; + } + if (res != ERROR_SUCCESS) { + return HRESULT_FROM_WIN32(res); + } + + for (auto p = OPTIONAL_FEATURES; p->regName; ++p) { + res = RegQueryValueExW(hKey, p->regName, nullptr, nullptr, nullptr, nullptr); + if (res == ERROR_FILE_NOT_FOUND) { + pEngine->SetVariableNumeric(p->variableName, 0); + } else if (res == ERROR_SUCCESS) { + pEngine->SetVariableNumeric(p->variableName, 1); + } else { + RegCloseKey(hKey); + return HRESULT_FROM_WIN32(res); + } + } + + RegCloseKey(hKey); + return S_OK; + } + + static HRESULT LoadTargetDirFromKey( + __in IBootstrapperEngine* pEngine, + __in HKEY hkHive, + __in LPCWSTR subkey + ) { + HKEY hKey; + LRESULT res; + DWORD dataType; + BYTE buffer[1024]; + DWORD bufferLen = sizeof(buffer); + + if (IsTargetPlatformx64(pEngine)) { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + } else { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); + } + if (res == ERROR_FILE_NOT_FOUND) { + return S_FALSE; + } + if (res != ERROR_SUCCESS) { + return HRESULT_FROM_WIN32(res); + } + + res = RegQueryValueExW(hKey, nullptr, nullptr, &dataType, buffer, &bufferLen); + if (res == ERROR_SUCCESS && dataType == REG_SZ && bufferLen < sizeof(buffer)) { + pEngine->SetVariableString(L"TargetDir", reinterpret_cast(buffer)); + } + RegCloseKey(hKey); + return HRESULT_FROM_WIN32(res); + } + + static HRESULT LoadLauncherStateFromKey( + __in IBootstrapperEngine* pEngine, + __in HKEY hkHive + ) { + const LPCWSTR subkey = L"Software\\Python\\PyLauncher"; + HKEY hKey; + LRESULT res; + + if (IsTargetPlatformx64(pEngine)) { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + } else { + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); + } + + if (res == ERROR_FILE_NOT_FOUND) { + return S_FALSE; + } + if (res != ERROR_SUCCESS) { + return HRESULT_FROM_WIN32(res); + } + + res = RegQueryValueExW(hKey, nullptr, nullptr, nullptr, nullptr, nullptr); + if (res == ERROR_FILE_NOT_FOUND) { + pEngine->SetVariableNumeric(L"Include_launcher", 0); + } else if (res == ERROR_SUCCESS) { + pEngine->SetVariableNumeric(L"Include_launcher", 1); + } + + res = RegQueryValueExW(hKey, L"AssociateFiles", nullptr, nullptr, nullptr, nullptr); + if (res == ERROR_FILE_NOT_FOUND) { + pEngine->SetVariableNumeric(L"AssociateFiles", 0); + } else if (res == ERROR_SUCCESS) { + pEngine->SetVariableNumeric(L"AssociateFiles", 1); + } + + RegCloseKey(hKey); + return S_OK; + } + + static void LoadOptionalFeatureStates(__in IBootstrapperEngine* pEngine) { + WCHAR subkeyFmt[256]; + WCHAR subkey[256]; + DWORD subkeyLen; + HRESULT hr; + HKEY hkHive; + + // The launcher installation is separate from the Python install, so we + // check its state later. This also checks the file association option. + + // Get the registry key from the bundle, to save having to duplicate it + // in multiple places. + subkeyLen = sizeof(subkeyFmt) / sizeof(subkeyFmt[0]); + hr = pEngine->GetVariableString(L"OptionalFeaturesRegistryKey", subkeyFmt, &subkeyLen); + BalExitOnFailure(hr, "Failed to locate registry key"); + subkeyLen = sizeof(subkey) / sizeof(subkey[0]); + hr = pEngine->FormatString(subkeyFmt, subkey, &subkeyLen); + BalExitOnFailure1(hr, "Failed to format %ls", subkeyFmt); + + // Check the current user's registry for existing features + hkHive = HKEY_CURRENT_USER; + hr = LoadOptionalFeatureStatesFromKey(pEngine, hkHive, subkey); + BalExitOnFailure1(hr, "Failed to read from HKCU\\%ls", subkey); + if (hr == S_FALSE) { + // Now check the local machine registry + hkHive = HKEY_LOCAL_MACHINE; + hr = LoadOptionalFeatureStatesFromKey(pEngine, hkHive, subkey); + BalExitOnFailure1(hr, "Failed to read from HKLM\\%ls", subkey); + if (hr == S_OK) { + // Found a system-wide install, so enable these settings. + pEngine->SetVariableNumeric(L"InstallAllUsers", 1); + pEngine->SetVariableNumeric(L"CompileAll", 1); + } + } + + if (hr == S_OK) { + // Cannot change InstallAllUsersState when upgrading. While there's + // no good reason to not allow installing a per-user and an all-user + // version simultaneously, Burn can't handle the state management + // and will need to uninstall the old one. + pEngine->SetVariableString(L"InstallAllUsersState", L"disable"); + + // Get the previous install directory. This can be changed by the + // user. + subkeyLen = sizeof(subkeyFmt) / sizeof(subkeyFmt[0]); + hr = pEngine->GetVariableString(L"TargetDirRegistryKey", subkeyFmt, &subkeyLen); + BalExitOnFailure(hr, "Failed to locate registry key"); + subkeyLen = sizeof(subkey) / sizeof(subkey[0]); + hr = pEngine->FormatString(subkeyFmt, subkey, &subkeyLen); + BalExitOnFailure1(hr, "Failed to format %ls", subkeyFmt); + LoadTargetDirFromKey(pEngine, hkHive, subkey); + } + + LExit: + return; + } public: // @@ -2667,7 +2852,8 @@ _installPage = PAGE_LOADING; _hrFinal = hrHostInitialization; - _downgrading = FALSE; + _downgradingOtherVersion = FALSE; + _upgradingOldVersion = FALSE; _restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE; _restartRequired = FALSE; _allowRestart = FALSE; @@ -2690,6 +2876,8 @@ _hBAFModule = nullptr; _baFunction = nullptr; + + LoadOptionalFeatureStates(pEngine); } @@ -2748,7 +2936,8 @@ DWORD _calculatedCacheProgress; DWORD _calculatedExecuteProgress; - BOOL _downgrading; + BOOL _downgradingOtherVersion; + BOOL _upgradingOldVersion; BOOTSTRAPPER_APPLY_RESTART _restartResult; BOOL _restartRequired; BOOL _allowRestart; diff --git a/Tools/msi/bundle/bootstrap/pythonba.vcxproj b/Tools/msi/bundle/bootstrap/pythonba.vcxproj --- a/Tools/msi/bundle/bootstrap/pythonba.vcxproj +++ b/Tools/msi/bundle/bootstrap/pythonba.vcxproj @@ -31,7 +31,7 @@ DynamicLibrary Unicode - $(ProjectDir)..\..\obj\$(Configuration)_Bootstrap\ + $(PySourcePath)PCBuild\obj\$(Configuration)_$(Platform)_Setup\Bootstrap\ $(IntDir) diff --git a/Tools/msi/bundle/bundle.wxs b/Tools/msi/bundle/bundle.wxs --- a/Tools/msi/bundle/bundle.wxs +++ b/Tools/msi/bundle/bundle.wxs @@ -23,14 +23,18 @@ - - + + + + + +